diff --git a/src/components/pageIm.ts b/src/components/pageIm.ts index df5321af..09731e6c 100644 --- a/src/components/pageIm.ts +++ b/src/components/pageIm.ts @@ -594,7 +594,11 @@ export default () => import('../lib/services').then(services => { //console.log('childnode str after:', str); - appMessagesManager.sendText(appImManager.peerID, str); + appMessagesManager.sendText(appImManager.peerID, str, { + replyToMsgID: appImManager.replyToMsgID == 0 ? undefined : appImManager.replyToMsgID + }); + appImManager.replyToMsgID = 0; + appImManager.replyElements.container.classList.remove('active'); appImManager.scroll.scrollTop = appImManager.scroll.scrollHeight; messageInput.innerText = ''; diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index b0d1624e..d703215d 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -146,6 +146,11 @@ export class AppDialogsManager { let dialog = dialogs[i]; if(!dialog.pFlags.pinned) break; pinnedDialogs.push(dialog); + + let dom = this.getDialogDom(dialog.peerID); + if(dom) { + dom.listEl.append(this.pinnedDelimiter); + } } let sorted = dialogs diff --git a/src/lib/appManagers/appImManager.ts b/src/lib/appManagers/appImManager.ts index 5797b906..7c615cd0 100644 --- a/src/lib/appManagers/appImManager.ts +++ b/src/lib/appManagers/appImManager.ts @@ -140,6 +140,13 @@ export class AppImManager { private contextMenuPin = this.contextMenu.querySelector('.menu-pin') as HTMLDivElement; private contextMenuMsgID: number; + public replyElements: { + container?: HTMLDivElement, + cancelBtn?: HTMLButtonElement, + titleEl?: HTMLDivElement, + subtitleEl?: HTMLDivElement + } = {}; + private popupDeleteMessage: { popupEl?: HTMLDivElement, deleteBothBtn?: HTMLButtonElement, @@ -147,6 +154,8 @@ export class AppImManager { cancelBtn?: HTMLButtonElement } = {}; + public replyToMsgID = 0; + constructor() { this.log = logger('IM'); @@ -157,6 +166,11 @@ export class AppImManager { this.popupDeleteMessage.deleteMeBtn = this.popupDeleteMessage.popupEl.querySelector('.popup-delete-me') as HTMLButtonElement; this.popupDeleteMessage.cancelBtn = this.popupDeleteMessage.popupEl.querySelector('.popup-close') as HTMLButtonElement; + this.replyElements.container = this.pageEl.querySelector('.reply-wrapper') as HTMLDivElement; + this.replyElements.cancelBtn = this.replyElements.container.querySelector('.reply-cancel') as HTMLButtonElement; + this.replyElements.titleEl = this.replyElements.container.querySelector('.reply-title') as HTMLDivElement; + this.replyElements.subtitleEl = this.replyElements.container.querySelector('.reply-subtitle') as HTMLDivElement; + apiManager.getUserID().then((id) => { this.myID = id; }); @@ -356,6 +370,15 @@ export class AppImManager { this.popupDeleteMessage.popupEl.classList.add('active'); }); + + this.contextMenu.querySelector('.menu-reply').addEventListener('click', () => { + let message = appMessagesManager.getMessage(this.contextMenuMsgID); + let title = appPeersManager.getPeerTitle(message.fromID).split(' ')[0]; + this.replyElements.titleEl.innerText = title; + this.replyElements.subtitleEl.innerText = message.message || ''; + this.replyElements.container.classList.add('active'); + this.replyToMsgID = this.contextMenuMsgID; + }); this.contextMenuPin.addEventListener('click', () => { apiManager.invokeApi('messages.updatePinnedMessage', { @@ -368,6 +391,11 @@ export class AppImManager { }); }); + this.replyElements.cancelBtn.addEventListener('click', () => { + this.replyElements.container.classList.remove('active'); + this.replyToMsgID = 0; + }); + this.popupDeleteMessage.deleteBothBtn.addEventListener('click', () => { this.deleteMessages(true); this.popupDeleteMessage.cancelBtn.click(); @@ -1113,7 +1141,7 @@ export class AppImManager { /* let fromTitle = */appPeersManager.getPeerTitle(fwd.from_id); } - if((this.peerID < 0 && !our) || message.fwd_from) { // chat + if((this.peerID < 0 && !our) || message.fwd_from || message.reply_to_mid) { // chat let title = appPeersManager.getPeerTitle(message.fwdFromID || message.fromID); //this.log(title); @@ -1152,6 +1180,7 @@ export class AppImManager { box.append(quote); bubble.append(box); + //bubble.classList.add('reply'); } /* if(message.media) { @@ -1171,7 +1200,7 @@ export class AppImManager { nameDiv.classList.add('name'); nameDiv.innerText = title; bubble.append(nameDiv); - } else { + } else if(!message.reply_to_mid) { bubble.classList.add('hide-name'); } @@ -1243,11 +1272,22 @@ export class AppImManager { let justDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); let dateTimestamp = justDate.getTime(); if(!(dateTimestamp in this.dateMessages)) { - const months = ['January', 'February', 'March', 'April', 'May', 'June', - 'July', 'August', 'September', 'October', 'November', 'December']; - let str = justDate.getFullYear() == new Date().getFullYear() ? - months[justDate.getMonth()] + ' ' + justDate.getDate() : - justDate.toISOString().split('T')[0].split('-').reverse().join('.'); + let str = ''; + + let today = new Date(); + today.setHours(0); + today.setMinutes(0); + today.setSeconds(0); + + if(today < date) { + str = 'Today'; + } else { + const months = ['January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', 'November', 'December']; + str = justDate.getFullYear() == new Date().getFullYear() ? + months[justDate.getMonth()] + ' ' + justDate.getDate() : + justDate.toISOString().split('T')[0].split('-').reverse().join('.'); + } let div = document.createElement('div'); div.classList.add('service'); diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index 6fec01e7..548ec3ad 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -188,7 +188,7 @@ export class AppMessagesManager { var message: any; if(historyStorage === undefined) { - historyStorage = this.historiesStorage[peerID] = {count: null, history: [], pending: []} + historyStorage = this.historiesStorage[peerID] = {count: null, history: [], pending: []}; } var fromID = appUsersManager.getSelf().id; @@ -203,14 +203,14 @@ export class AppMessagesManager { } if(replyToMsgID) { - flags |= 8 + flags |= 8; } if(asChannel) { - fromID = 0 - pFlags.post = true + fromID = 0; + pFlags.post = true; } else { - flags |= 256 + flags |= 256; } message = { @@ -340,7 +340,7 @@ export class AppMessagesManager { if(this.pendingAfterMsgs[peerID] === sentRequestOptions) { delete this.pendingAfterMsgs[peerID]; } - }) + }); this.pendingAfterMsgs[peerID] = sentRequestOptions; } diff --git a/src/lib/appManagers/appSidebarRight.ts b/src/lib/appManagers/appSidebarRight.ts index e1a7bfc9..4a11af69 100644 --- a/src/lib/appManagers/appSidebarRight.ts +++ b/src/lib/appManagers/appSidebarRight.ts @@ -21,6 +21,7 @@ class AppSidebarRight { bio: this.profileContentEl.querySelector('.profile-row-bio') as HTMLDivElement, username: this.profileContentEl.querySelector('.profile-row-username') as HTMLDivElement, phone: this.profileContentEl.querySelector('.profile-row-phone') as HTMLDivElement, + notificationsRow: this.profileContentEl.querySelector('.profile-row-notifications') as HTMLDivElement, notificationsCheckbox: this.profileContentEl.querySelector('#profile-notifications') as HTMLInputElement, notificationsStatus: this.profileContentEl.querySelector('.profile-row-notifications > p') as HTMLParagraphElement }; @@ -69,23 +70,53 @@ class AppSidebarRight { private peerID = 0; public sidebarScroll: Scrollable = null; + private savedVirtualStates: { + [id: number]: { + hiddenElements: any, + paddings: any + } + } + + private profileTabs: HTMLUListElement; + private prevTabID = -1; constructor() { let container = this.profileContentEl.querySelector('.profile-tabs-content') as HTMLDivElement; - let tabs = this.profileContentEl.querySelector('.profile-tabs') as HTMLUListElement; + this.profileTabs = this.profileContentEl.querySelector('.profile-tabs') as HTMLUListElement; this.sidebarScroll = new Scrollable(this.sidebarEl); this.sidebarScroll.container.addEventListener('scroll', this.onSidebarScroll.bind(this)); - horizontalMenu(tabs, container, (id, tabContent) => { + horizontalMenu(this.profileTabs, container, (id, tabContent) => { this.sharedMediaType = this.sharedMediaTypes[id]; this.sharedMediaSelected = tabContent.firstElementChild as HTMLDivElement; - this.log('setVirtualContainer', this.sharedMediaSelected); + if(this.prevTabID != -1) { + this.savedVirtualStates[this.prevTabID] = { + hiddenElements: { + up: this.sidebarScroll.hiddenElements.up.slice(), + down: this.sidebarScroll.hiddenElements.down.slice(), + }, + paddings: { + up: this.sidebarScroll.paddings.up, + down: this.sidebarScroll.paddings.down + } + }; + } + + this.prevTabID = id; + + this.log('setVirtualContainer', id, this.sharedMediaSelected); this.sidebarScroll.setVirtualContainer(this.sharedMediaSelected); + + if(this.savedVirtualStates[id]) { + this.log(this.savedVirtualStates[id]); + this.sidebarScroll.hiddenElements = this.savedVirtualStates[id].hiddenElements; + this.sidebarScroll.paddings = this.savedVirtualStates[id].paddings; + } }, this.onSidebarScroll.bind(this)); - (tabs.children[1] as HTMLLIElement).click(); // set media + //(this.profileTabs.children[1] as HTMLLIElement).click(); // set media let sidebarCloseBtn = this.sidebarEl.querySelector('.sidebar-close-button') as HTMLButtonElement; sidebarCloseBtn.addEventListener('click', () => { @@ -297,14 +328,21 @@ class AppSidebarRight { this.loadSidebarMediaPromises = {}; this.lastSharedMediaDiv = document.createElement('div'); + this.log('fillProfileElements'); + + this.savedVirtualStates = {}; + this.prevTabID = -1; + (this.profileTabs.children[1] as HTMLLIElement).click(); // set media + if(this.sharedMediaSelected) { - this.sidebarScroll.setVirtualContainer(this.sharedMediaSelected); + //this.sidebarScroll.setVirtualContainer(this.sharedMediaSelected); } this.profileContentEl.parentElement.scrollTop = 0; this.profileElements.bio.style.display = 'none'; this.profileElements.phone.style.display = 'none'; this.profileElements.username.style.display = 'none'; + this.profileElements.notificationsRow.style.display = ''; this.profileElements.notificationsCheckbox.checked = true; this.profileElements.notificationsStatus.innerText = 'Enabled'; @@ -329,14 +367,16 @@ class AppSidebarRight { }; // username - let username = appPeersManager.getPeerUsername(peerID); - if(username) { - setText(appPeersManager.getPeerUsername(peerID), this.profileElements.username); + if(peerID != appImManager.myID) { + let username = appPeersManager.getPeerUsername(peerID); + if(username) { + setText(appPeersManager.getPeerUsername(peerID), this.profileElements.username); + } } if(peerID > 0) { let user = appUsersManager.getUser(peerID); - if(user.phone) { + if(user.phone && peerID != appImManager.myID) { setText('+' + formatPhoneNumber(user.phone).formatted, this.profileElements.phone); } @@ -346,7 +386,7 @@ class AppSidebarRight { return; } - if(userFull.rAbout) { + if(userFull.rAbout && peerID != appImManager.myID) { setText(userFull.rAbout, this.profileElements.bio); } @@ -374,15 +414,19 @@ class AppSidebarRight { }); } - let dialog: any = appMessagesManager.getDialogByPeerID(peerID); - if(dialog.length) { - dialog = dialog[0]; - let muted = false; - if(dialog.notify_settings && dialog.notify_settings.mute_until) { - muted = new Date(dialog.notify_settings.mute_until * 1000) > new Date(); + if(peerID != appImManager.myID) { + let dialog: any = appMessagesManager.getDialogByPeerID(peerID); + if(dialog.length) { + dialog = dialog[0]; + let muted = false; + if(dialog.notify_settings && dialog.notify_settings.mute_until) { + muted = new Date(dialog.notify_settings.mute_until * 1000) > new Date(); + } + + appImManager.setMutedState(muted); } - - appImManager.setMutedState(muted); + } else { + this.profileElements.notificationsRow.style.display = 'none'; } //this.loadSidebarMedia(); diff --git a/src/scss/partials/_chat.scss b/src/scss/partials/_chat.scss index a7ba9fc7..8d199e69 100644 --- a/src/scss/partials/_chat.scss +++ b/src/scss/partials/_chat.scss @@ -94,54 +94,6 @@ } } } - - .pinned-message { - cursor: pointer; - display: flex; - flex-direction: row; - align-items: center; - overflow: hidden; - box-sizing: border-box; - width: 150px; - margin-right: 1rem; - max-height: 35px; - /* padding: .25rem; */ - - &:hover { - background-color: rgba(112, 117, 121, 0.08); - } - - .pinned-message-border { - height: 32px; - border-radius: 1px; - min-width: 2px; - background: $blue; - } - - .pinned-message-content { - margin-left: 8px; - flex-grow: 1; - flex-shrink: 1; - overflow: hidden; - pointer-events: none; - } - - .pinned-message-title { - color: $blue; - } - - .pinned-message-title, .pinned-message-subtitle { - font-size: 14px; - line-height: 18px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - .pinned-message-subtitle { - white-space: nowrap; - } - } } #bubbles { @@ -418,6 +370,7 @@ .name { font-weight: 500; + display: inline!important; } &:not(.web) { @@ -720,14 +673,15 @@ .input-message { display: flex; align-items: center; + flex-direction: column; width: calc(100% - 3.75rem); - justify-content: space-between; + justify-content: center; background-color: #fff; border-radius: 12px; border-bottom-right-radius: 0; box-shadow: 0 1px 2px 0 rgba(16, 35, 47, 0.07); margin-right: .5rem; - padding: 0 .5rem; + padding: 4.5px .5rem; min-height: 3.25rem; max-height: 30rem; caret-color: $button-primary-background; @@ -747,6 +701,41 @@ transform: scaleX(-1); } + > div { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + //min-height: inherit; + } + + .reply-wrapper { + justify-content: flex-start; + overflow: hidden; + transition: .2s all; + height: 0px; + + &.active { + height: 35px; + } + + .reply { + width: 100%; + margin-left: .5rem; + min-height: 35px; + } + } + + .new-message-wrapper { + //padding: 4.5px 0; + //padding-bottom: 4.5px; + align-items: flex-end; + + .btn-icon:before { + vertical-align: middle; + } + } + .input-message-container { width: 1%; max-height: inherit; @@ -804,6 +793,7 @@ width: 3.25rem; color: #9e9e9e; background-color: #fff; + align-self: flex-end; &.tgico-send { color: $blue; @@ -815,6 +805,54 @@ } } + .pinned-message, .reply { + cursor: pointer; + display: flex; + flex-direction: row; + align-items: center; + overflow: hidden; + box-sizing: border-box; + width: 150px; + margin-right: 1rem; + max-height: 35px; + /* padding: .25rem; */ + + &:hover { + background-color: rgba(112, 117, 121, 0.08); + } + + &-border { + height: 32px; + border-radius: 1px; + min-width: 2px; + background: $blue; + } + + &-content { + margin-left: 8px; + flex-grow: 1; + flex-shrink: 1; + overflow: hidden; + pointer-events: none; + } + + &-title { + color: $blue; + } + + &-title, &-subtitle { + font-size: 14px; + line-height: 18px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + &-subtitle { + white-space: nowrap; + } + } + /* #chat-closed { position: absolute; left: 0; diff --git a/src/scss/partials/_chatlist.scss b/src/scss/partials/_chatlist.scss index 16e3c330..639baf3e 100644 --- a/src/scss/partials/_chatlist.scss +++ b/src/scss/partials/_chatlist.scss @@ -99,10 +99,15 @@ align-items: center; height: 1.7rem; // hot-fix - span:not(.tgico-pinnedchat):not(.emoji):last-child { + /* span:not(.tgico-pinnedchat):not(.emoji):last-child { */ + .user-title + span { /* font-size: .9rem; */ font-size: .8rem; } + + .user-last-message + span:not(.tgico-pinnedchat) { + font-size: .9rem; + } } span {