From ebd532b6088652eec2f453d7fb30c84f33db618f Mon Sep 17 00:00:00 2001 From: sairajzero Date: Fri, 13 Sep 2019 01:15:49 +0530 Subject: [PATCH] Added UI for group options Added custom checkbox list for selecting users in group options Added buttons to invoke group options Hover on the 'more-options' (3-dot) button in the top-right corner to view group options Note : group options will only be displayed when user is either creator or admin of respective group --- app/app.js | 333 ++++++++++++++++++++++++++++++++----------------- app/index.html | 43 +++++-- app/styles.css | 150 ++++++++++++++++++---- 3 files changed, 375 insertions(+), 151 deletions(-) diff --git a/app/app.js b/app/app.js index ba47fa5..e811a9a 100644 --- a/app/app.js +++ b/app/app.js @@ -322,7 +322,7 @@ function userDataStartUp() { } }); document.getElementById("searchContact").addEventListener("input", searchContact, true); - + document.getElementById("searchList").addEventListener("input", searchChecklist, true); getDatafromAPI().then(result => { console.log(result); getContactsfromIDB().then(result => { @@ -1012,11 +1012,12 @@ function checkStatusInterval() { function changeReceiver(param) { if (receiverID !== undefined) document.getElementById(receiverID).style.display = 'none'; - console.log(param.getAttribute("name")); + //console.log(param.getAttribute("name")); receiverID = param.getAttribute("name"); document.getElementById('recipient-floID').innerHTML = receiverID; receiverStatus(false) document.getElementById(receiverID).style.display = 'block'; + document.getElementById("groupOptions").style.display = 'none'; if (receiverID in contacts) { msgType = 'direct'; @@ -1051,6 +1052,21 @@ function changeReceiver(param) { if (receiverWebSocket !== undefined && receiverWebSocket.readyState === WebSocket.OPEN) receiverWebSocket.close() receiverWebSocket = undefined; + if (selfID == groups[receiverID].creator) { + var grpOpt = document.getElementById("groupOptions"); + grpOpt.style.display = 'block'; + var optList = grpOpt.querySelectorAll('li'); + for (var i = 0; i < optList.length; i++) + optList[i].style.display = 'block'; + } else if (groups[receiverID].admins.includes(selfID)) { + var grpOpt = document.getElementById("groupOptions"); + grpOpt.style.display = 'block'; + var optList = grpOpt.querySelectorAll('li'); + for (var i = 0; i < 2; i++) + optList[i].style.display = 'block'; + for (var i = 2; i < optList.length; i++) + optList[i].style.display = 'none'; + } } } @@ -1291,27 +1307,29 @@ function deleteGroupFromIDB(groupID) { } function createGroup() { - var members = prompt("Enter Members FLO_ID : "); - var grpName = prompt("Enter Group Name : "); - - var grpInfo = floOpt.genNewIDpair(); - grpInfo.name = grpName; - grpInfo.members = members.split(','); - grpInfo.creator = selfID; - grpInfo.admins = []; - var grpInfoStr = JSON.stringify(grpInfo); - console.log(grpInfoStr); - var data = { - from: selfID, - newGroup: { - sign: floOpt.signData(grpInfoStr, privKey) + customCheckList(Object.keys(contacts), [selfID], 'Create Group', 'success').then(result => { + var grpInfo = floOpt.genNewIDpair(); + grpInfo.name = result.grpName; + grpInfo.members = result.members; + grpInfo.members.push(selfID) + grpInfo.creator = selfID; + grpInfo.admins = []; + var grpInfoStr = JSON.stringify(grpInfo); + console.log(grpInfoStr); + var data = { + from: selfID, + newGroup: { + sign: floOpt.signData(grpInfoStr, privKey) + } } - } - grpInfo.members.forEach(floID => { - data.to = floID; - data.newGroup.groupInfo = floOpt.encryptData(grpInfoStr, contacts[floID].pubKey), - sendData(floID, JSON.stringify(data)); - }); + grpInfo.members.forEach(floID => { + data.to = floID; + data.newGroup.groupInfo = floOpt.encryptData(grpInfoStr, contacts[floID].pubKey), + sendData(floID, JSON.stringify(data)); + }); + }).catch(error => { + console.log(error); + }) } function deleteGroup() { @@ -1332,113 +1350,125 @@ function deleteGroup() { } function addGroupMembers() { - var newMembers = prompt("Enter new Members : "); - newMembers = newMembers.split(','); - var data1 = { - from: selfID, - addGroupMembers: { - group: receiverID, - members: newMembers, - sign: floOpt.signData('addGroupMembers:' + receiverID + newMembers.join('|'), privKey) + customCheckList(Object.keys(contacts), groups[receiverID].members, 'Add Members', 'success').then(result => { + var newMembers = result.members; + var data1 = { + from: selfID, + addGroupMembers: { + group: receiverID, + members: newMembers, + sign: floOpt.signData('addGroupMembers:' + receiverID + newMembers.join('|'), privKey) + } } - } - groups[receiverID].members.forEach(floID => { - if (floID == selfID) //dont send to self - return; - data1.to = floID; - sendData(floID, JSON.stringify(data1)); - }); - groups[receiverID].members = groups[receiverID].members.concat(newMembers); - var grpInfoStr = JSON.stringify(groups[receiverID]); - console.log(grpInfoStr); - var data2 = { - from: selfID, - newGroup: { - sign: floOpt.signData(grpInfoStr, privKey) + groups[receiverID].members.forEach(floID => { + if (floID == selfID) //dont send to self + return; + data1.to = floID; + sendData(floID, JSON.stringify(data1)); + }); + groups[receiverID].members = groups[receiverID].members.concat(newMembers); + var grpInfoStr = JSON.stringify(groups[receiverID]); + console.log(grpInfoStr); + var data2 = { + from: selfID, + newGroup: { + sign: floOpt.signData(grpInfoStr, privKey) + } } - } - newMembers.forEach(floID => { - data2.to = floID; - data2.newGroup.groupInfo = floOpt.encryptData(grpInfoStr, contacts[floID].pubKey), - sendData(floID, JSON.stringify(data2)); - }); - storeGroup(grpInfoStr, receiverID); + newMembers.forEach(floID => { + data2.to = floID; + data2.newGroup.groupInfo = floOpt.encryptData(grpInfoStr, contacts[floID].pubKey), + sendData(floID, JSON.stringify(data2)); + }); + storeGroup(grpInfoStr, receiverID); + }).catch(error => { + console.log(error); + }) } function rmGroupMembers() { - var rmMembers = prompt("Enter Members to remove : "); - rmMembers = rmMembers.split(','); - var data1 = { - from: selfID, - rmGroupMembers: { - group: receiverID, - members: rmMembers, - sign: floOpt.signData('rmGroupMembers:' + receiverID + rmMembers.join('|'), privKey) + customCheckList(groups[receiverID].members, [], 'Remove Members', 'danger').then(result => { + var rmMembers = result.members; + var data1 = { + from: selfID, + rmGroupMembers: { + group: receiverID, + members: rmMembers, + sign: floOpt.signData('rmGroupMembers:' + receiverID + rmMembers.join('|'), privKey) + } } - } - groups[receiverID].members = groups[receiverID].members.filter(x => !rmMembers.includes(x)); //remove member from group - storeGroup(JSON.stringify(groups[receiverID]), receiverID); - groups[receiverID].members.forEach(floID => { - if (floID == selfID) - return; - data1.to = floID; - sendData(floID, JSON.stringify(data1)); - }); - var data2 = { - from: selfID, - deleteGroup: { - group: receiverID, - sign: floOpt.signData('deleteGroup:' + receiverID, privKey) - } - }; - rmMembers.forEach(floID => { - data2.to = floID; - sendData(floID, JSON.stringify(data2)); - }); + groups[receiverID].members = groups[receiverID].members.filter(x => !rmMembers.includes(x)); //remove member from group + storeGroup(JSON.stringify(groups[receiverID]), receiverID); + groups[receiverID].members.forEach(floID => { + if (floID == selfID) + return; + data1.to = floID; + sendData(floID, JSON.stringify(data1)); + }); + var data2 = { + from: selfID, + deleteGroup: { + group: receiverID, + sign: floOpt.signData('deleteGroup:' + receiverID, privKey) + } + }; + rmMembers.forEach(floID => { + data2.to = floID; + sendData(floID, JSON.stringify(data2)); + }); + }).catch(error => { + console.log(error); + }) } function addGroupAdmins() { - var newAdmins = prompt("Enter new Admins : "); - newAdmins = newAdmins.split(','); - var data = { - from: selfID, - addGroupAdmins: { - group: receiverID, - admins: newAdmins, - sign: floOpt.signData('addGroupAdmins:' + receiverID + newAdmins.join('|'), privKey) + customCheckList(groups[receiverID].members, groups[receiverID].admins, 'Add Admins', 'success').then(result => { + var newAdmins = result.members; + var data = { + from: selfID, + addGroupAdmins: { + group: receiverID, + admins: newAdmins, + sign: floOpt.signData('addGroupAdmins:' + receiverID + newAdmins.join('|'), privKey) + } } - } - groups[receiverID].members.forEach(floID => { - if (floID == selfID) //dont send to self - return; - data.to = floID; - sendData(floID, JSON.stringify(data)); - }); - groups[receiverID].admins = groups[receiverID].admins.concat(newAdmins); - var grpInfoStr = JSON.stringify(groups[receiverID]); - storeGroup(grpInfoStr, receiverID); + groups[receiverID].members.forEach(floID => { + if (floID == selfID) //dont send to self + return; + data.to = floID; + sendData(floID, JSON.stringify(data)); + }); + groups[receiverID].admins = groups[receiverID].admins.concat(newAdmins); + var grpInfoStr = JSON.stringify(groups[receiverID]); + storeGroup(grpInfoStr, receiverID); + }).catch(error => { + console.log(error); + }) } function rmGroupAdmins() { - var rmAdmins = prompt("Enter rmAdmins: "); - rmAdmins = rmAdmins.split(','); - var data = { - from: selfID, - rmGroupAdmins: { - group: receiverID, - admins: rmAdmins, - sign: floOpt.signData('rmGroupAdmins:' + receiverID + rmAdmins.join('|'), privKey) + customCheckList(groups[receiverID].admins, [], 'Remove Admins', 'danger').then(result => { + var rmAdmins = result.members; + var data = { + from: selfID, + rmGroupAdmins: { + group: receiverID, + admins: rmAdmins, + sign: floOpt.signData('rmGroupAdmins:' + receiverID + rmAdmins.join('|'), privKey) + } } - } - groups[receiverID].members.forEach(floID => { - if (floID == selfID) //dont send to self - return; - data.to = floID; - sendData(floID, JSON.stringify(data)); - }); - groups[receiverID].admins = groups[receiverID].admins.filter(x => !rmAdmins.includes(x)); //remove admins - var grpInfoStr = JSON.stringify(groups[receiverID]); - storeGroup(grpInfoStr, receiverID); + groups[receiverID].members.forEach(floID => { + if (floID == selfID) //dont send to self + return; + data.to = floID; + sendData(floID, JSON.stringify(data)); + }); + groups[receiverID].admins = groups[receiverID].admins.filter(x => !rmAdmins.includes(x)); //remove admins + var grpInfoStr = JSON.stringify(groups[receiverID]); + storeGroup(grpInfoStr, receiverID); + }).catch(error => { + console.log(error); + }) } function searchContact() { @@ -1458,4 +1488,77 @@ function searchContact() { } catch (e) { console.log(e); } +} + +function customCheckList(userList, ignoreList, okBtnVal = "Ok", okBtnType = "success") { + var dialog = document.getElementById('overlay'); + dialog.style.display = "block"; + var okButton = dialog.querySelector('button.ok'); + var cancelButton = dialog.querySelector('button.cancel'); + okButton.setAttribute("class", `ok btn btn-${okBtnType}`); + okButton.innerHTML = okBtnVal; + var grpNameInput = dialog.querySelector('input.grpName') + grpNameInput.style.display = (okBtnVal === "Create Group" ? "block" : "none"); + grpNameInput.value = ''; + var userChecklist = document.getElementById('userChecklist'); + for (var i = 0; i < userList.length; i++) { + if (ignoreList.includes(userList[i])) + continue; + var listEl = document.createElement('label'); + listEl.setAttribute('class', "btn btn-default listLabel"); + listEl.setAttribute('name', userList[i]); + listEl.innerHTML = ` + ${contacts[userList[i]].name}
+ @${userList[i]} +
+ + `; + userChecklist.appendChild(listEl); + } + return new Promise((resolve, reject) => { + dialog.addEventListener('click', function handleButtonClicks(e) { + if (e.target.tagName !== 'BUTTON') { + return; + } + dialog.removeEventListener('click', handleButtonClicks); + dialog.style.display = 'none'; + if (e.target === okButton) { + var selectedList = []; + var checklist = dialog.querySelectorAll('input.badgebox'); + for (var i = 0; i < checklist.length; i++) + if (checklist[i].checked) + selectedList.push(checklist[i].value); + if (selectedList.length == 0) + reject('User Didnt select Any Users!'); + else + resolve({ + grpName: grpNameInput.value, + members: selectedList + }); + } else if (e.target === cancelButton) { + reject('User cancelled!'); + } else { + reject('Some other button was clicked!'); + } + }); + }); +} + +function searchChecklist() { + try { + var searchKey = this.value; + if (!searchKey) + var searchResults = Object.keys(contacts); + else + var searchResults = searchIndex.search(searchKey); + var checklist = document.getElementById('userChecklist').children; + for (var i = 0; i < checklist.length; i++) { + if (searchResults.includes(checklist[i].getAttribute("name"))) + checklist[i].style.display = 'block'; + else + checklist[i].style.display = 'none'; + }; + } catch (e) { + console.log(e); + } } \ No newline at end of file diff --git a/app/index.html b/app/index.html index 7ee0c31..a190cf1 100644 --- a/app/index.html +++ b/app/index.html @@ -15,7 +15,25 @@ - + + +
+
+ + +
+ + +
+
+
@@ -30,10 +48,10 @@
--> -
+
-
+
created by Ranchimall
@@ -63,14 +81,20 @@
- O   Select Contact + O   Select Contact
-
@@ -87,14 +111,15 @@
-->
- +
-
+
diff --git a/app/styles.css b/app/styles.css index fbb4fac..25a356b 100644 --- a/app/styles.css +++ b/app/styles.css @@ -43,6 +43,7 @@ body { margin: 0 !important; height: 100%; } + .side-one { padding: 0; margin: 0; @@ -68,7 +69,6 @@ body { } - .heading { padding: 10px 16px 10px 15px; margin: 0 !important; @@ -107,19 +107,21 @@ body { display: block; } -#recipient-status{ +#recipient-status { border-radius: 50%; - background: none; + background: none; height: 25px; width: 25px; - color:white; + color: white; } + .heading-online { display: none; padding: 0 5px; font-size: 12px; color: #93918f; } + .heading-compose { padding: 0; } @@ -157,7 +159,6 @@ body { background-color: #fbfbfb; } - /*#searchBox-inner input { box-shadow: none; }*/ @@ -244,6 +245,7 @@ body { position: relative; left: -100%; } + .newMessage-heading { padding: 10px 16px 10px 15px !important; margin: 0 !important; @@ -268,6 +270,7 @@ body { font-weight: 700; padding: 10px 5px !important; } + .newMessage-back { text-align: center; vertical-align: baseline; @@ -275,6 +278,7 @@ body { display: block; cursor: pointer; } + .newMessage-back i { margin: auto !important; } @@ -328,25 +332,9 @@ body { border: 1px solid #f7f7f7; height: calc(100% - 120px); } -.message-inner{ - overflow-y: auto; -} -.message-previous { - margin : 0 !important; - padding: 0 !important; - height: auto; - width: 100%; -} -.previous { - font-size: 15px; - text-align: center; - padding: 10px !important; - cursor: pointer; -} -.previous a { - text-decoration: none; - font-weight: 700; +.message-inner { + overflow-y: auto; } .message-body { @@ -372,7 +360,7 @@ body { .message-text { margin: 0 !important; padding: 5px !important; - word-wrap:break-word; + word-wrap: break-word; font-weight: 200; font-size: 14px; padding-bottom: 0 !important; @@ -386,7 +374,6 @@ body { text-align: right; color: #9a9a9a; height: auto; - } .receiver { @@ -399,7 +386,6 @@ body { word-wrap: break-word; display: inline-block; height: auto; - } .sender { @@ -414,7 +400,6 @@ body { word-wrap: break-word; } - /*Reply*/ .reply { @@ -488,66 +473,84 @@ body { top: 0; height: 100%; } + .heading { height: 70px; background-color: #009688; } + .fa-2x { font-size: 2.3em !important; } + .heading-avatar { padding: 0 !important; } + .heading-avatar-icon img { height: 50px; width: 50px; } + .heading-compose { padding: 5px !important; } + .heading-compose i { color: #fff; cursor: pointer; } + .heading-dot { padding: 5px !important; margin-left: 10px !important; } + .heading-dot i { color: #fff; cursor: pointer; } + .sideBar { height: calc(100% - 130px); } + .sideBar-body { height: 80px; } + .sideBar-avatar { text-align: left; padding: 0 8px !important; } + .avatar-icon img { height: 55px; width: 55px; } + .sideBar-main { padding: 0 !important; } + .sideBar-main .row { padding: 0 !important; margin: 0 !important; } + .sideBar-name { padding: 10px 5px !important; } + .name-meta { font-size: 16px; padding: 5% !important; } + .sideBar-time { padding: 10px !important; } + .time-meta { text-align: right; font-size: 14px; @@ -555,6 +558,7 @@ body { color: rgba(0, 0, 0, .4); vertical-align: baseline; } + /*Conversation*/ .conversation { padding: 0 !important; @@ -564,38 +568,130 @@ body { border-left: 1px solid rgba(0, 0, 0, .08); /*overflow-y: auto;*/ } + .message { height: calc(100% - 140px); } + .reply { height: 70px; } + .reply-emojis { padding: 5px 0 !important; } + .reply-emojis i { padding: 5px 2px !important; font-size: 1.8em !important; } + .reply-main { padding: 2px 8px !important; } + .reply-main input { padding: 8px !important; font-size: 18px; } + .reply-recording { padding: 5px 0 !important; } + .reply-recording i { padding: 5px 0 !important; font-size: 1.8em !important; } + .reply-send { padding: 5px 0 !important; } + .reply-send i { padding: 5px 2px 5px 0 !important; font-size: 1.8em !important; } +} + +.badgebox { + opacity: 0; +} + +.badgebox+.badge { + height: 14px; + width: 20px; + font-size: 0px; + padding: 2px; + float: right; +} + +.badgebox:focus+.badge { + box-shadow: inset 0px 0px 3px; +} + +.badgebox:checked+.badge { + font-size: inherit; +} + +.listLabel { + margin: 5px; + text-align: left; + line-height: 50%; + padding: 10px; + display: block; +} + +#overlay { + width: 100%; + height: 100%; + text-align: center; + position: fixed; + top: 0; + z-index: 2; + background-color: rgba(0, 0, 0, .5); + display: none; +} + +.userChecklist-container { + margin-top: 25px; + width: 300px; + height: 400px; + background-color: #eee; + display: inline-block; +} + +#userChecklist { + height: 275px; + overflow-y: auto; +} + +.dropdown-content { + display: none; + position: absolute; + min-width: 150px; + z-index: 1; + cursor: pointer; + margin-left: -75px; +} + +.dropdown-content li { + color: rgb(95, 95, 95); + padding: 12px 16px; + text-decoration: none; + display: block; + text-align: right; + background-color: #ddd; +} + +.dropdown-content li:hover { + background-color: #aaa; +} + +.dropdown:hover .dropdown-content { + display: block; +} + +#groupOptions { + display: none; } \ No newline at end of file