diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index 6e514e15c..626846aac 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -886,6 +886,8 @@ dlgPaddingVer: 8px; dlgHeight: 62px; dlgPhotoPadding: 12px; +dlgImportantHeight: 37px; + noContactsHeight: 100px; noContactsFont: font(fsize); noContactsColor: #777; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 07d0b9d0f..83596d4e7 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -245,7 +245,7 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt if (!h->isEmpty()) { h->clear(true); } - if (hto->inChatList() && h->inChatList()) { + if (hto->inChatList(Dialogs::Mode::All) && h->inChatList(Dialogs::Mode::All)) { App::removeDialog(h); } } diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index c07ee3f82..6d11b479b 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -557,7 +557,7 @@ namespace { if (!h->isEmpty()) { h->clear(true); } - if (hto->inChatList() && h->inChatList()) { + if (hto->inChatList(Dialogs::Mode::All) && h->inChatList(Dialogs::Mode::All)) { App::removeDialog(h); } } @@ -1137,8 +1137,8 @@ namespace { } else { if (channelHistory) { channelHistory->messageWithIdDeleted(i->v); - if (channelHistory->unreadCount > 0 && i->v >= channelHistory->inboxReadBefore) { - channelHistory->setUnreadCount(channelHistory->unreadCount - 1); + if (channelHistory->unreadCount() > 0 && i->v >= channelHistory->inboxReadBefore) { + channelHistory->setUnreadCount(channelHistory->unreadCount() - 1); } } } diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index f107dc93c..d3e7a9c7c 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -962,6 +962,15 @@ void AppClass::onSwitchDebugMode() { } } +void AppClass::onSwitchWorkMode() { + Global::SetDialogsModeEnabled(!Global::DialogsModeEnabled()); + Global::SetDialogsMode(Dialogs::Mode::All); + Local::writeUserSettings(); + cSetRestarting(true); + cSetRestartingToSettings(true); + App::quit(); +} + void AppClass::onSwitchTestMode() { if (cTestMode()) { QFile(cWorkingDir() + qsl("tdata/withtestmode")).remove(); diff --git a/Telegram/SourceFiles/application.h b/Telegram/SourceFiles/application.h index 3e0a37e56..ae51569e8 100644 --- a/Telegram/SourceFiles/application.h +++ b/Telegram/SourceFiles/application.h @@ -195,6 +195,7 @@ public slots: void photoUpdated(const FullMsgId &msgId, bool silent, const MTPInputFile &file); void onSwitchDebugMode(); + void onSwitchWorkMode(); void onSwitchTestMode(); void killDownloadSessions(); diff --git a/Telegram/SourceFiles/boxes/addcontactbox.cpp b/Telegram/SourceFiles/boxes/addcontactbox.cpp index f2d85354d..7e58787bc 100644 --- a/Telegram/SourceFiles/boxes/addcontactbox.cpp +++ b/Telegram/SourceFiles/boxes/addcontactbox.cpp @@ -1183,7 +1183,7 @@ EditChannelBox::EditChannelBox(ChannelData *channel) : AbstractBox() , _saveTitleRequestId(0) , _saveDescriptionRequestId(0) , _saveSignRequestId(0) { - connect(App::main(), SIGNAL(peerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)), this, SLOT(peerUpdated(PeerData*))); + connect(App::main(), SIGNAL(peerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&)), this, SLOT(peerUpdated(PeerData*))); setMouseTracking(true); diff --git a/Telegram/SourceFiles/boxes/contactsbox.cpp b/Telegram/SourceFiles/boxes/contactsbox.cpp index b00b68f8a..e9fdcfc65 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.cpp +++ b/Telegram/SourceFiles/boxes/contactsbox.cpp @@ -1757,7 +1757,7 @@ MembersInner::MembersInner(ChannelData *channel, MembersFilter filter) : TWidget , _about(_aboutWidth) , _aboutHeight(0) { connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); - connect(App::main(), SIGNAL(peerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&))); + connect(App::main(), SIGNAL(peerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&))); connect(App::main(), SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(peerUpdated(PeerData*))); refresh(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_common.h b/Telegram/SourceFiles/dialogs/dialogs_common.h index a7f7de725..dd45fea13 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_common.h +++ b/Telegram/SourceFiles/dialogs/dialogs_common.h @@ -26,9 +26,14 @@ class Row; using RowsByLetter = QMap<QChar, Row*>; enum class SortMode { - Date, - Name, - Add + Date = 0x00, + Name = 0x01, + Add = 0x02, +}; + +enum class Mode { + All = 0x00, + Important = 0x01, }; } // namespace Dialogs diff --git a/Telegram/SourceFiles/dialogs/dialogs_indexed_list.cpp b/Telegram/SourceFiles/dialogs/dialogs_indexed_list.cpp index af6ef8ebe..7c262f3aa 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_indexed_list.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_indexed_list.cpp @@ -71,72 +71,85 @@ void IndexedList::adjustByPos(const RowsByLetter &links) { } } - void IndexedList::peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) { + t_assert(_sortMode != SortMode::Date); if (_sortMode == SortMode::Name) { - Row *mainRow = _list.adjustByName(peer); - if (!mainRow) return; - - History *history = mainRow->history(); - - PeerData::NameFirstChars toRemove = oldChars, toAdd; - for_const (auto ch, peer->chars) { - auto j = toRemove.find(ch); - if (j == toRemove.cend()) { - toAdd.insert(ch); - } else { - toRemove.erase(j); - if (auto list = _index.value(ch)) { - list->adjustByName(peer); - } - } - } - for_const (auto ch, toRemove) { - if (auto list = _index.value(ch)) { - list->del(peer->id, mainRow); - } - } - if (!toAdd.isEmpty()) { - for_const (auto ch, toAdd) { - auto j = _index.find(ch); - if (j == _index.cend()) { - j = _index.insert(ch, new List(_sortMode)); - } - j.value()->addByName(history); - } - } + adjustByName(peer, oldNames, oldChars); } else { - auto mainRow = _list.getRow(peer->id); - if (!mainRow) return; + adjustNames(Dialogs::Mode::All, peer, oldNames, oldChars); + } +} - History *history = mainRow->history(); +void IndexedList::peerNameChanged(Mode list, PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) { + t_assert(_sortMode == SortMode::Date); + adjustNames(list, peer, oldNames, oldChars); +} - PeerData::NameFirstChars toRemove = oldChars, toAdd; - for_const (auto ch, peer->chars) { - auto j = toRemove.find(ch); - if (j == toRemove.cend()) { - toAdd.insert(ch); - } else { - toRemove.erase(j); - } - } - for_const (auto ch, toRemove) { - if (_sortMode == SortMode::Date) { - history->removeChatListEntryByLetter(ch); - } +void IndexedList::adjustByName(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) { + Row *mainRow = _list.adjustByName(peer); + if (!mainRow) return; + + History *history = mainRow->history(); + + PeerData::NameFirstChars toRemove = oldChars, toAdd; + for_const (auto ch, peer->chars) { + auto j = toRemove.find(ch); + if (j == toRemove.cend()) { + toAdd.insert(ch); + } else { + toRemove.erase(j); if (auto list = _index.value(ch)) { - list->del(peer->id, mainRow); + list->adjustByName(peer); } } + } + for_const (auto ch, toRemove) { + if (auto list = _index.value(ch)) { + list->del(peer->id, mainRow); + } + } + if (!toAdd.isEmpty()) { for_const (auto ch, toAdd) { auto j = _index.find(ch); if (j == _index.cend()) { j = _index.insert(ch, new List(_sortMode)); } - Row *row = j.value()->addToEnd(history); - if (_sortMode == SortMode::Date) { - history->addChatListEntryByLetter(ch, row); - } + j.value()->addByName(history); + } + } +} + +void IndexedList::adjustNames(Mode list, PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) { + auto mainRow = _list.getRow(peer->id); + if (!mainRow) return; + + History *history = mainRow->history(); + + PeerData::NameFirstChars toRemove = oldChars, toAdd; + for_const (auto ch, peer->chars) { + auto j = toRemove.find(ch); + if (j == toRemove.cend()) { + toAdd.insert(ch); + } else { + toRemove.erase(j); + } + } + for_const (auto ch, toRemove) { + if (_sortMode == SortMode::Date) { + history->removeChatListEntryByLetter(list, ch); + } + if (auto list = _index.value(ch)) { + list->del(peer->id, mainRow); + } + } + for_const (auto ch, toAdd) { + auto j = _index.find(ch); + if (j == _index.cend()) { + j = _index.insert(ch, new List(_sortMode)); + } + Row *row = j.value()->addToEnd(history); + if (_sortMode == SortMode::Date) { + history->addChatListEntryByLetter(list, ch, row); } } } diff --git a/Telegram/SourceFiles/dialogs/dialogs_indexed_list.h b/Telegram/SourceFiles/dialogs/dialogs_indexed_list.h index e0acfd0aa..6a5967977 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_indexed_list.h +++ b/Telegram/SourceFiles/dialogs/dialogs_indexed_list.h @@ -34,7 +34,13 @@ public: RowsByLetter addToEnd(History *history); Row *addByName(History *history); void adjustByPos(const RowsByLetter &links); + + // For sortMode != SortMode::Date void peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars); + + //For sortMode == SortMode::Date + void peerNameChanged(Mode list, PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars); + void del(const PeerData *peer, Row *replacedBy = nullptr); void clear(); @@ -71,6 +77,9 @@ public: iterator find(int y, int h) { return all().find(y, h); } private: + void adjustByName(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars); + void adjustNames(Mode list, PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars); + SortMode _sortMode; List _list; using Index = QMap<QChar, List*>; diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp index 855bede73..d9c5fbc22 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp @@ -170,41 +170,48 @@ void paintUnreadBadge(Painter &p, const QRect &rect, bool active, bool muted) { p.drawPixmap(rect.x() + sizehalf + bar, rect.y(), unreadBadgeStyle->right[index]); } +void paintUnreadCount(Painter &p, const QString &text, int top, int w, bool active, bool muted, int *outAvailableWidth) { + int unreadWidth = st::dlgUnreadFont->width(text); + int unreadRectWidth = unreadWidth + 2 * st::dlgUnreadPaddingHor; + int unreadRectHeight = st::dlgUnreadHeight; + accumulate_max(unreadRectWidth, unreadRectHeight); + + int unreadRectLeft = w - st::dlgPaddingHor - unreadRectWidth; + int unreadRectTop =top; + if (outAvailableWidth) { + *outAvailableWidth -= unreadRectWidth + st::dlgUnreadPaddingHor; + } + + paintUnreadBadge(p, QRect(unreadRectLeft, unreadRectTop, unreadRectWidth, unreadRectHeight), active, muted); + + p.setFont(st::dlgUnreadFont); + p.setPen(active ? st::dlgActiveUnreadColor : st::dlgUnreadColor); + p.drawText(unreadRectLeft + (unreadRectWidth - unreadWidth) / 2, unreadRectTop + st::dlgUnreadTop + st::dlgUnreadFont->ascent, text); +} + } // namepsace void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool selected, bool onlyBackground) { auto history = row->history(); auto item = history->lastMsg; paintRow(p, history, item, w, active, selected, onlyBackground, [&p, w, active, history, item](int nameleft, int namewidth) { - int32 lastWidth = namewidth, unread = history->unreadCount; + int32 unread = history->unreadCount(); if (history->peer->migrateFrom()) { if (History *h = App::historyLoaded(history->peer->migrateFrom()->id)) { - unread += h->unreadCount; + unread += h->unreadCount(); } } + int availableWidth = namewidth; int texttop = st::dlgPaddingVer + st::dlgFont->height + st::dlgSep; if (unread) { - QString unreadStr = QString::number(unread); - int unreadWidth = st::dlgUnreadFont->width(unreadStr); - int unreadRectWidth = unreadWidth + 2 * st::dlgUnreadPaddingHor; - int unreadRectHeight = st::dlgUnreadHeight; - accumulate_max(unreadRectWidth, unreadRectHeight); - - int unreadRectLeft = w - st::dlgPaddingHor - unreadRectWidth; - int unreadRectTop = texttop + st::dlgHistFont->ascent - st::dlgUnreadFont->ascent - st::dlgUnreadTop; - lastWidth -= unreadRectWidth + st::dlgUnreadPaddingHor; - - paintUnreadBadge(p, QRect(unreadRectLeft, unreadRectTop, unreadRectWidth, unreadRectHeight), active, history->mute); - - p.setFont(st::dlgUnreadFont); - p.setPen(active ? st::dlgActiveUnreadColor : st::dlgUnreadColor); - p.drawText(unreadRectLeft + (unreadRectWidth - unreadWidth) / 2, unreadRectTop + st::dlgUnreadTop + st::dlgUnreadFont->ascent, unreadStr); + int unreadTop = texttop + st::dlgHistFont->ascent - st::dlgUnreadFont->ascent - st::dlgUnreadTop; + paintUnreadCount(p, QString::number(unread), unreadTop, w, active, history->mute(), &availableWidth); } if (history->typing.isEmpty() && history->sendActions.isEmpty()) { - item->drawInDialog(p, QRect(nameleft, texttop, lastWidth, st::dlgFont->height), active, history->textCachedFor, history->lastItemTextCache); + item->drawInDialog(p, QRect(nameleft, texttop, availableWidth, st::dlgFont->height), active, history->textCachedFor, history->lastItemTextCache); } else { p.setPen(active ? st::dlgActiveColor : st::dlgSystemColor); - history->typingText.drawElided(p, nameleft, texttop, lastWidth); + history->typingText.drawElided(p, nameleft, texttop, availableWidth); } }); } @@ -218,6 +225,28 @@ void RowPainter::paint(Painter &p, const FakeRow *row, int w, bool active, bool }); } +void paintImportantSwitch(Painter &p, Mode current, int w, bool selected, bool onlyBackground) { + p.fillRect(0, 0, w, st::dlgImportantHeight, selected ? st::dlgHoverBG : st::white); + if (onlyBackground) { + return; + } + + p.setFont(st::semiboldFont); + p.setPen(st::black); + + int unreadTop = (st::dlgImportantHeight - st::dlgUnreadHeight) / 2; + bool mutedHidden = (current == Dialogs::Mode::Important); + QString text = mutedHidden ? qsl("Show all chats") : qsl("Hide muted chats"); + int textBaseline = unreadTop + st::dlgUnreadTop + st::dlgUnreadFont->ascent; + p.drawText(st::dlgPaddingHor, textBaseline, text); + + if (mutedHidden) { + if (int32 unread = App::histories().unreadMutedCount()) { + paintUnreadCount(p, QString::number(unread), unreadTop, w, false, true, nullptr); + } + } +} + namespace { using StyleSheets = OrderedSet<StyleSheet**>; diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.h b/Telegram/SourceFiles/dialogs/dialogs_layout.h index fd1908625..1c0de56a1 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.h +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.h @@ -33,6 +33,8 @@ public: static void paint(Painter &p, const FakeRow *row, int w, bool active, bool selected, bool onlyBackground); }; +void paintImportantSwitch(Painter &p, Mode current, int w, bool selected, bool onlyBackground); + // This will be moved somewhere outside as soon as anyone starts using that. class StyleSheet { public: diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index 81274388d..297ba54d4 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -40,6 +40,9 @@ DialogsInner::DialogsInner(QWidget *parent, MainWidget *main) : SplittedWidget(p , contacts(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Name)) , _addContactLnk(this, lang(lng_add_contact_button)) , _cancelSearchInPeer(this, st::btnCancelSearch) { + if (Global::DialogsModeEnabled()) { + importantDialogs = std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Date); + } connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); connect(main, SIGNAL(peerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&))); connect(main, SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(onPeerPhotoChanged(PeerData*))); @@ -50,16 +53,20 @@ DialogsInner::DialogsInner(QWidget *parent, MainWidget *main) : SplittedWidget(p refresh(); } -int32 DialogsInner::filteredOffset() const { +int DialogsInner::dialogsOffset() const { + return importantDialogs ? st::dlgImportantHeight : 0; +} + +int DialogsInner::filteredOffset() const { return _hashtagResults.size() * st::mentionHeight; } -int32 DialogsInner::peopleOffset() const { +int DialogsInner::peopleOffset() const { return filteredOffset() + (_filterResults.size() * st::dlgHeight) + st::searchedBarHeight; } -int32 DialogsInner::searchedOffset() const { - int32 result = peopleOffset() + (_peopleResults.isEmpty() ? 0 : ((_peopleResults.size() * st::dlgHeight) + st::searchedBarHeight)); +int DialogsInner::searchedOffset() const { + int result = peopleOffset() + (_peopleResults.isEmpty() ? 0 : ((_peopleResults.size() * st::dlgHeight) + st::searchedBarHeight)); if (_searchInPeer) result += st::dlgHeight; return result; } @@ -76,16 +83,22 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO } if (_state == DefaultState) { - int32 otherStart = dialogs->size() * st::dlgHeight; - PeerData *active = App::main()->activePeer(), *selected = _menuPeer ? _menuPeer : (sel ? sel->history()->peer : 0); + QRect dialogsClip = r; + if (importantDialogs) { + Dialogs::Layout::paintImportantSwitch(p, Global::DialogsMode(), fullWidth(), _importantSwitchSel, paintingOther); + dialogsClip.translate(0, -st::dlgImportantHeight); + p.translate(0, st::dlgImportantHeight); + } + int32 otherStart = shownDialogs()->size() * st::dlgHeight; + PeerData *active = App::main()->activePeer(), *selected = _menuPeer ? _menuPeer : (_sel ? _sel->history()->peer : 0); if (otherStart) { - dialogs->all().paint(p, fullWidth(), r.top(), r.top() + r.height(), active, selected, paintingOther); + shownDialogs()->all().paint(p, fullWidth(), dialogsClip.top(), dialogsClip.top() + dialogsClip.height(), active, selected, paintingOther); } if (!otherStart) { - p.fillRect(r, st::white->b); + p.fillRect(dialogsClip, st::white); if (!paintingOther) { - p.setFont(st::noContactsFont->f); - p.setPen(st::noContactsColor->p); + p.setFont(st::noContactsFont); + p.setPen(st::noContactsColor); p.drawText(QRect(0, 0, fullWidth(), st::noContactsHeight - (cContactsReceived() ? st::noContactsFont->height : 0)), lang(cContactsReceived() ? lng_no_chats : lng_contacts_loading), style::al_center); } } @@ -223,13 +236,11 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO } } -void DialogsInner::peopleResultPaint(PeerData *peer, Painter &p, int32 w, bool act, bool sel, bool onlyBackground) const { +void DialogsInner::peopleResultPaint(PeerData *peer, Painter &p, int32 w, bool active, bool selected, bool onlyBackground) const { QRect fullRect(0, 0, w, st::dlgHeight); - p.fillRect(fullRect, (act ? st::dlgActiveBG : (sel ? st::dlgHoverBG : st::dlgBG))->b); + p.fillRect(fullRect, active ? st::dlgActiveBG : (selected ? st::dlgHoverBG : st::dlgBG)); if (onlyBackground) return; - History *history = App::history(peer->id); - PeerData *userpicPeer = (peer->migrateTo() ? peer->migrateTo() : peer); userpicPeer->paintUserpicLeft(p, st::dlgPhotoSize, st::dlgPaddingHor, st::dlgPaddingVer, fullWidth()); @@ -239,21 +250,21 @@ void DialogsInner::peopleResultPaint(PeerData *peer, Painter &p, int32 w, bool a // draw chat icon if (peer->isChat() || peer->isMegagroup()) { - p.drawPixmap(QPoint(rectForName.left() + st::dlgChatImgPos.x(), rectForName.top() + st::dlgChatImgPos.y()), App::sprite(), (act ? st::dlgActiveChatImg : st::dlgChatImg)); + p.drawSprite(QPoint(rectForName.left() + st::dlgChatImgPos.x(), rectForName.top() + st::dlgChatImgPos.y()), (active ? st::dlgActiveChatImg : st::dlgChatImg)); rectForName.setLeft(rectForName.left() + st::dlgImgSkip); } else if (peer->isChannel()) { - p.drawPixmap(QPoint(rectForName.left() + st::dlgChannelImgPos.x(), rectForName.top() + st::dlgChannelImgPos.y()), App::sprite(), (act ? st::dlgActiveChannelImg : st::dlgChannelImg)); + p.drawSprite(QPoint(rectForName.left() + st::dlgChannelImgPos.x(), rectForName.top() + st::dlgChannelImgPos.y()), (active ? st::dlgActiveChannelImg : st::dlgChannelImg)); rectForName.setLeft(rectForName.left() + st::dlgImgSkip); } if (peer->isVerified()) { rectForName.setWidth(rectForName.width() - st::verifiedCheck.pxWidth() - st::verifiedCheckPos.x()); - p.drawSprite(rectForName.topLeft() + QPoint(qMin(peer->dialogName().maxWidth(), rectForName.width()), 0) + st::verifiedCheckPos, (act ? st::verifiedCheckInv : st::verifiedCheck)); + p.drawSprite(rectForName.topLeft() + QPoint(qMin(peer->dialogName().maxWidth(), rectForName.width()), 0) + st::verifiedCheckPos, (active ? st::verifiedCheckInv : st::verifiedCheck)); } QRect tr(nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, namewidth, st::dlgFont->height); p.setFont(st::dlgHistFont->f); QString username = peer->userName(); - if (!act && username.toLower().startsWith(_peopleQuery)) { + if (!active && username.toLower().startsWith(_peopleQuery)) { QString first = '@' + username.mid(0, _peopleQuery.size()), second = username.mid(_peopleQuery.size()); int32 w = st::dlgHistFont->width(first); if (w >= tr.width()) { @@ -266,11 +277,11 @@ void DialogsInner::peopleResultPaint(PeerData *peer, Painter &p, int32 w, bool a p.drawText(tr.left() + w, tr.top() + st::dlgHistFont->ascent, st::dlgHistFont->elided(second, tr.width() - w)); } } else { - p.setPen((act ? st::dlgActiveColor : st::dlgSystemColor)->p); + p.setPen((active ? st::dlgActiveColor : st::dlgSystemColor)->p); p.drawText(tr.left(), tr.top() + st::dlgHistFont->ascent, st::dlgHistFont->elided('@' + username, tr.width())); } - p.setPen((act ? st::dlgActiveColor : st::dlgNameColor)->p); + p.setPen((active ? st::dlgActiveColor : st::dlgNameColor)->p); peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); } @@ -308,24 +319,26 @@ void DialogsInner::activate() { void DialogsInner::mouseMoveEvent(QMouseEvent *e) { lastMousePos = mapToGlobal(e->pos()); - selByMouse = true; + _selByMouse = true; onUpdateSelected(true); } void DialogsInner::onUpdateSelected(bool force) { QPoint mouse(mapFromGlobal(lastMousePos)); - if ((!force && !rect().contains(mouse)) || !selByMouse) return; + if ((!force && !rect().contains(mouse)) || !_selByMouse) return; int w = width(), mouseY = mouse.y(); _overDelete = false; if (_state == DefaultState) { - auto newSel = dialogs->rowAtY(mouseY, st::dlgHeight); - int otherStart = dialogs->size() * st::dlgHeight; - if (newSel != sel) { + auto newImportantSwitchSel = (importantDialogs && mouseY >= 0 && mouseY < dialogsOffset()); + mouseY -= dialogsOffset(); + auto newSel = newImportantSwitchSel ? nullptr : shownDialogs()->rowAtY(mouseY, st::dlgHeight); + if (newSel != _sel || newImportantSwitchSel != _importantSwitchSel) { updateSelectedRow(); - sel = newSel; + _sel = newSel; + _importantSwitchSel = newImportantSwitchSel; updateSelectedRow(); - setCursor(sel ? style::cur_pointer : style::cur_default); + setCursor(_sel ? style::cur_pointer : style::cur_default); } } else if (_state == FilteredState || _state == SearchedState) { if (!_hashtagResults.isEmpty()) { @@ -384,7 +397,7 @@ void DialogsInner::onUpdateSelected(bool force) { void DialogsInner::mousePressEvent(QMouseEvent *e) { lastMousePos = mapToGlobal(e->pos()); - selByMouse = true; + _selByMouse = true; onUpdateSelected(true); if (e->button() == Qt::LeftButton) { choosePeer(); @@ -411,25 +424,46 @@ void DialogsInner::onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRo } } } - if (sel == oldRow) { - sel = newRow; + if (_sel == oldRow) { + _sel = newRow; } } void DialogsInner::createDialog(History *history) { - bool creating = !history->inChatList(); + bool creating = !history->inChatList(Dialogs::Mode::All); if (creating) { - Dialogs::Row *mainRow = history->addToChatList(dialogs.get()); + Dialogs::Row *mainRow = history->addToChatList(Dialogs::Mode::All, dialogs.get()); contactsNoDialogs->del(history->peer, mainRow); } - RefPair(int32, movedFrom, int32, movedTo) = history->adjustByPosInChatsList(dialogs.get()); + if (importantDialogs && !history->inChatList(Dialogs::Mode::Important) && !history->mute()) { + if (Global::DialogsMode() == Dialogs::Mode::Important) { + creating = true; + } + history->addToChatList(Dialogs::Mode::Important, importantDialogs.get()); + } + + auto changed = history->adjustByPosInChatList(Dialogs::Mode::All, dialogs.get()); + + if (importantDialogs) { + if (history->mute()) { + if (Global::DialogsMode() == Dialogs::Mode::Important) { + return; + } + } else { + auto importantChanged = history->adjustByPosInChatList(Dialogs::Mode::Important, importantDialogs.get()); + if (Global::DialogsMode() == Dialogs::Mode::Important) { + changed = importantChanged; + } + } + } + RefPair(int32, movedFrom, int32, movedTo) = changed; emit dialogMoved(movedFrom, movedTo); if (creating) { refresh(); } else if (_state == DefaultState && movedFrom != movedTo) { - update(0, qMin(movedFrom, movedTo), fullWidth(), qAbs(movedFrom - movedTo) + st::dlgHeight); + update(0, dialogsOffset() + qMin(movedFrom, movedTo), fullWidth(), qAbs(movedFrom - movedTo) + st::dlgHeight); } } @@ -438,10 +472,13 @@ void DialogsInner::removeDialog(History *history) { if (history->peer == _menuPeer && _menu) { _menu->deleteLater(); } - if (sel && sel->history() == history) { - sel = nullptr; + if (_sel && _sel->history() == history) { + _sel = nullptr; + } + history->removeFromChatList(Dialogs::Mode::All, dialogs.get()); + if (importantDialogs) { + history->removeFromChatList(Dialogs::Mode::Important, importantDialogs.get()); } - history->removeFromChatList(dialogs.get()); history->clearNotifications(); if (App::wnd()) App::wnd()->notifyClear(history); if (contacts->contains(history->peer->id)) { @@ -457,14 +494,18 @@ void DialogsInner::removeDialog(History *history) { refresh(); } -void DialogsInner::dlgUpdated(Dialogs::Row *row) { +void DialogsInner::dlgUpdated(Dialogs::Mode list, Dialogs::Row *row) { if (_state == DefaultState) { - update(0, row->pos() * st::dlgHeight, fullWidth(), st::dlgHeight); + if (Global::DialogsMode() == list) { + update(0, dialogsOffset() + row->pos() * st::dlgHeight, fullWidth(), st::dlgHeight); + } } else if (_state == FilteredState || _state == SearchedState) { - for (int32 i = 0, l = _filterResults.size(); i < l; ++i) { - if (_filterResults.at(i)->history() == row->history()) { - update(0, i * st::dlgHeight, fullWidth(), st::dlgHeight); - break; + if (list == Dialogs::Mode::All) { + for (int32 i = 0, l = _filterResults.size(); i < l; ++i) { + if (_filterResults.at(i)->history() == row->history()) { + update(0, i * st::dlgHeight, fullWidth(), st::dlgHeight); + break; + } } } } @@ -472,8 +513,8 @@ void DialogsInner::dlgUpdated(Dialogs::Row *row) { void DialogsInner::dlgUpdated(History *history, MsgId msgId) { if (_state == DefaultState) { - if (auto row = dialogs->getRow(history->peer->id)) { - update(0, row->pos() * st::dlgHeight, fullWidth(), st::dlgHeight); + if (auto row = shownDialogs()->getRow(history->peer->id)) { + update(0, dialogsOffset() + row->pos() * st::dlgHeight, fullWidth(), st::dlgHeight); } } else if (_state == FilteredState || _state == SearchedState) { int32 cnt = 0, add = filteredOffset(); @@ -517,12 +558,14 @@ void DialogsInner::updateSelectedRow(PeerData *peer) { if (_state == DefaultState) { if (peer) { if (History *h = App::historyLoaded(peer->id)) { - if (h->inChatList()) { - update(0, h->posInChatList() * st::dlgHeight, fullWidth(), st::dlgHeight); + if (h->inChatList(Global::DialogsMode())) { + update(0, dialogsOffset() + h->posInChatList(Global::DialogsMode()) * st::dlgHeight, fullWidth(), st::dlgHeight); } } - } else if (sel) { - update(0, sel->pos() * st::dlgHeight, fullWidth(), st::dlgHeight); + } else if (_sel) { + update(0, dialogsOffset() + _sel->pos() * st::dlgHeight, fullWidth(), st::dlgHeight); + } else if (_importantSwitchSel) { + update(0, 0, fullWidth(), st::dlgImportantHeight); } } else if (_state == FilteredState || _state == SearchedState) { if (peer) { @@ -547,10 +590,15 @@ void DialogsInner::updateSelectedRow(PeerData *peer) { void DialogsInner::leaveEvent(QEvent *e) { setMouseTracking(false); - selByMouse = false; - if (sel || _filteredSel >= 0 || _hashtagSel >= 0 || _searchedSel >= 0 || _peopleSel >= 0) { + clearSelection(); +} + +void DialogsInner::clearSelection() { + _selByMouse = false; + if (_sel || _filteredSel >= 0 || _hashtagSel >= 0 || _searchedSel >= 0 || _peopleSel >= 0) { updateSelectedRow(); - sel = 0; + _sel = nullptr; + _importantSwitchSel = false; _filteredSel = _searchedSel = _peopleSel = _hashtagSel = -1; setCursor(style::cur_default); } @@ -569,13 +617,13 @@ void DialogsInner::contextMenuEvent(QContextMenuEvent *e) { if (e->reason() == QContextMenuEvent::Mouse) { lastMousePos = e->globalPos(); - selByMouse = true; + _selByMouse = true; onUpdateSelected(true); } History *history = 0; if (_state == DefaultState) { - if (sel) history = sel->history(); + if (_sel) history = _sel->history(); } else if (_state == FilteredState || _state == SearchedState) { if (_filteredSel >= 0 && _filteredSel < _filterResults.size()) { history = _filterResults[_filteredSel]->history(); @@ -691,7 +739,7 @@ void DialogsInner::onMenuDestroyed(QObject *obj) { } lastMousePos = QCursor::pos(); if (rect().contains(mapFromGlobal(lastMousePos))) { - selByMouse = true; + _selByMouse = true; setMouseTracking(true); onUpdateSelected(true); } @@ -707,7 +755,10 @@ void DialogsInner::onParentGeometryChanged() { } void DialogsInner::onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) { - dialogs->peerNameChanged(peer, oldNames, oldChars); + dialogs->peerNameChanged(Dialogs::Mode::All, peer, oldNames, oldChars); + if (importantDialogs) { + importantDialogs->peerNameChanged(Dialogs::Mode::Important, peer, oldNames, oldChars); + } contactsNoDialogs->peerNameChanged(peer, oldNames, oldChars); contacts->peerNameChanged(peer, oldNames, oldChars); update(); @@ -889,10 +940,10 @@ void DialogsInner::peerUpdated(PeerData *peer) { PeerData *DialogsInner::updateFromParentDrag(QPoint globalPos) { lastMousePos = globalPos; - selByMouse = true; + _selByMouse = true; onUpdateSelected(true); if (_state == DefaultState) { - if (sel) return sel->history()->peer; + if (_sel) return _sel->history()->peer; } else if (_state == FilteredState || _state == SearchedState) { if (_filteredSel >= 0 && _filteredSel < _filterResults.size()) { return _filterResults[_filteredSel]->history()->peer; @@ -976,8 +1027,9 @@ void DialogsInner::dialogsReceived(const QVector<MTPDialog> &added) { } if (App::wnd()) App::wnd()->updateCounter(); - if (!sel && !dialogs->isEmpty()) { - sel = *dialogs->cbegin(); + if (!_sel && !shownDialogs()->isEmpty()) { + _sel = *shownDialogs()->cbegin(); + _importantSwitchSel = false; } refresh(); } @@ -1042,7 +1094,7 @@ void DialogsInner::peopleReceived(const QString &query, const QVector<MTPPeer> & for (QVector<MTPPeer>::const_iterator i = people.cbegin(), e = people.cend(); i != e; ++i) { PeerId peerId = peerFromMTP(*i); if (History *h = App::historyLoaded(peerId)) { - if (h->inChatList()) { + if (h->inChatList(Dialogs::Mode::All)) { continue; // skip existing chats } } @@ -1069,16 +1121,17 @@ void DialogsInner::notify_userIsContactChanged(UserData *user, bool fromThisApp) if (user->contact > 0) { History *history = App::history(user->id); contacts->addByName(history); - if (auto row = dialogs->getRow(user->id)) { + if (auto row = shownDialogs()->getRow(user->id)) { if (fromThisApp) { - sel = row; + _sel = row; + _importantSwitchSel = false; } - } else { + } else if (!dialogs->contains(user->id)) { contactsNoDialogs->addByName(history); } } else { - if (sel && sel->history()->peer == user) { - sel = nullptr; + if (_sel && _sel->history()->peer == user) { + _sel = nullptr; } contactsNoDialogs->del(user); contacts->del(user); @@ -1086,19 +1139,54 @@ void DialogsInner::notify_userIsContactChanged(UserData *user, bool fromThisApp) refresh(); } +void DialogsInner::notify_historyMuteUpdated(History *history) { + if (!importantDialogs || !history->inChatList(Dialogs::Mode::All)) return; + + if (history->mute()) { + if (_sel && _sel->history() == history && Global::DialogsMode() == Dialogs::Mode::Important) { + _sel = nullptr; + } + history->removeFromChatList(Dialogs::Mode::Important, importantDialogs.get()); + if (Global::DialogsMode() != Dialogs::Mode::Important) { + return; + } + refresh(); + } else { + bool creating = !history->inChatList(Dialogs::Mode::Important); + if (creating) { + history->addToChatList(Dialogs::Mode::Important, importantDialogs.get()); + } + + auto changed = history->adjustByPosInChatList(Dialogs::Mode::All, dialogs.get()); + + if (Global::DialogsMode() != Dialogs::Mode::Important) { + return; + } + RefPair(int32, movedFrom, int32, movedTo) = changed; + + emit dialogMoved(movedFrom, movedTo); + + if (creating) { + refresh(); + } else if (_state == DefaultState && movedFrom != movedTo) { + update(0, dialogsOffset() + qMin(movedFrom, movedTo), fullWidth(), qAbs(movedFrom - movedTo) + st::dlgHeight); + } + } +} + void DialogsInner::refresh(bool toTop) { int32 h = 0; if (_state == DefaultState) { - h = (dialogs->size()/* + contactsNoDialogs->size()*/) * st::dlgHeight; - if (h) { - if (!_addContactLnk.isHidden()) _addContactLnk.hide(); - } else { + if (shownDialogs()->isEmpty()) { h = st::noContactsHeight; if (cContactsReceived()) { if (_addContactLnk.isHidden()) _addContactLnk.show(); } else { if (!_addContactLnk.isHidden()) _addContactLnk.hide(); } + } else { + h = dialogsOffset() + shownDialogs()->size() * st::dlgHeight; + if (!_addContactLnk.isHidden()) _addContactLnk.hide(); } } else { if (!_addContactLnk.isHidden()) _addContactLnk.hide(); @@ -1117,10 +1205,11 @@ void DialogsInner::refresh(bool toTop) { } void DialogsInner::setMouseSel(bool msel, bool toTop) { - selByMouse = msel; - if (!selByMouse && toTop) { + _selByMouse = msel; + if (!_selByMouse && toTop) { if (_state == DefaultState) { - sel = !dialogs->isEmpty() ? *dialogs->cbegin() : nullptr; + _sel = !shownDialogs()->isEmpty() ? *shownDialogs()->cbegin() : nullptr; + _importantSwitchSel = false; } else if (_state == FilteredState || _state == SearchedState) { // don't select first elem in search _filteredSel = _peopleSel = _searchedSel = _hashtagSel = -1; setCursor(style::cur_default); @@ -1182,25 +1271,39 @@ void DialogsInner::clearFilter() { void DialogsInner::selectSkip(int32 direction) { if (_state == DefaultState) { - if (!sel) { - if (!dialogs->isEmpty() && direction > 0) { - sel = *dialogs->cbegin(); + if (_importantSwitchSel) { + if (!shownDialogs()->isEmpty() && direction > 0) { + _sel = *shownDialogs()->cbegin(); + _importantSwitchSel = false; + } else { + return; + } + } else if (!_sel) { + if (importantDialogs) { + _importantSwitchSel = true; + } else if (!shownDialogs()->isEmpty() && direction > 0) { + _sel = *shownDialogs()->cbegin(); } else { return; } } else if (direction > 0) { - auto next = dialogs->cfind(sel); - if (++next != dialogs->cend()) { - sel = *next; + auto next = shownDialogs()->cfind(_sel); + if (++next != shownDialogs()->cend()) { + _sel = *next; } } else { - auto prev = dialogs->cfind(sel); - if (prev != dialogs->cbegin()) { - sel = *(--prev); + auto prev = shownDialogs()->cfind(_sel); + if (prev != shownDialogs()->cbegin()) { + _sel = *(--prev); + } else if (importantDialogs) { + _importantSwitchSel = true; + _sel = nullptr; } } - int32 fromY = sel->pos() * st::dlgHeight; - emit mustScrollTo(fromY, fromY + st::dlgHeight); + if (_importantSwitchSel || _sel) { + int fromY = _importantSwitchSel ? 0 : (dialogsOffset() + _sel->pos() * st::dlgHeight); + emit mustScrollTo(fromY, fromY + st::dlgHeight); + } } else if (_state == FilteredState || _state == SearchedState) { if (_hashtagResults.isEmpty() && _filterResults.isEmpty() && _peopleResults.isEmpty() && _searchResults.isEmpty()) return; if ((_hashtagSel < 0 || _hashtagSel >= _hashtagResults.size()) && @@ -1249,8 +1352,8 @@ void DialogsInner::selectSkip(int32 direction) { void DialogsInner::scrollToPeer(const PeerId &peer, MsgId msgId) { int32 fromY = -1; if (_state == DefaultState) { - if (auto row = dialogs->getRow(peer)) { - fromY = row->pos() * st::dlgHeight; + if (auto row = shownDialogs()->getRow(peer)) { + fromY = dialogsOffset() + row->pos() * st::dlgHeight; } } else if (_state == FilteredState || _state == SearchedState) { if (msgId) { @@ -1278,24 +1381,31 @@ void DialogsInner::scrollToPeer(const PeerId &peer, MsgId msgId) { void DialogsInner::selectSkipPage(int32 pixels, int32 direction) { int toSkip = pixels / int(st::dlgHeight); if (_state == DefaultState) { - if (!sel) { - if (direction > 0 && !dialogs->isEmpty()) { - sel = *dialogs->cbegin(); + if (!_sel) { + if (direction > 0 && !shownDialogs()->isEmpty()) { + _sel = *shownDialogs()->cbegin(); + _importantSwitchSel = false; } else { return; } } if (direction > 0) { - for (auto i = dialogs->cfind(sel), end = dialogs->cend(); i != end && (toSkip--); ++i) { - sel = *i; + for (auto i = shownDialogs()->cfind(_sel), end = shownDialogs()->cend(); i != end && (toSkip--); ++i) { + _sel = *i; } } else { - for (auto i = dialogs->cfind(sel), b = dialogs->cbegin(); i != b && (toSkip--); --i) { - sel = *i; + for (auto i = shownDialogs()->cfind(_sel), b = shownDialogs()->cbegin(); i != b && (toSkip--); --i) { + _sel = *i; + } + if (toSkip && importantDialogs) { + _importantSwitchSel = true; + _sel = nullptr; } } - int fromY = sel->pos() * st::dlgHeight; - emit mustScrollTo(fromY, fromY + st::dlgHeight); + if (_importantSwitchSel || _sel) { + int fromY = (_importantSwitchSel ? 0 : (dialogsOffset() + _sel->pos() * st::dlgHeight)); + emit mustScrollTo(fromY, fromY + st::dlgHeight); + } } else { return selectSkip(direction * toSkip); } @@ -1308,9 +1418,9 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) { int32 yTo = yFrom + parentWidget()->height() * 5; MTP::clearLoaderPriorities(); if (_state == DefaultState) { - int32 otherStart = dialogs->size() * st::dlgHeight; + int32 otherStart = shownDialogs()->size() * st::dlgHeight; if (yFrom < otherStart) { - for (auto i = dialogs->cfind(yFrom, st::dlgHeight), end = dialogs->cend(); i != end; ++i) { + for (auto i = shownDialogs()->cfind(yFrom, st::dlgHeight), end = shownDialogs()->cend(); i != end; ++i) { if (((*i)->pos() * st::dlgHeight) >= yTo) { break; } @@ -1357,10 +1467,23 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) { } bool DialogsInner::choosePeer() { - History *history = 0; + History *history = nullptr; MsgId msgId = ShowAtUnreadMsgId; if (_state == DefaultState) { - if (sel) history = sel->history(); + if (_importantSwitchSel && importantDialogs) { + clearSelection(); + if (Global::DialogsMode() == Dialogs::Mode::All) { + Global::SetDialogsMode(Dialogs::Mode::Important); + } else { + Global::SetDialogsMode(Dialogs::Mode::All); + } + Local::writeUserSettings(); + refresh(); + _importantSwitchSel = true; + return true; + } else if (_sel) { + history = _sel->history(); + } } else if (_state == FilteredState || _state == SearchedState) { if (_hashtagSel >= 0 && _hashtagSel < _hashtagResults.size()) { QString hashtag = _hashtagResults.at(_hashtagSel); @@ -1379,7 +1502,7 @@ bool DialogsInner::choosePeer() { Local::writeRecentHashtagsAndBots(); emit refreshHashtags(); - selByMouse = true; + _selByMouse = true; onUpdateSelected(true); } else { saveRecentHashtags('#' + hashtag); @@ -1406,7 +1529,7 @@ bool DialogsInner::choosePeer() { emit searchResultChosen(); } updateSelectedRow(); - sel = 0; + _sel = nullptr; _filteredSel = _peopleSel = _searchedSel = _hashtagSel = -1; return true; } @@ -1442,7 +1565,7 @@ void DialogsInner::saveRecentHashtags(const QString &text) { } void DialogsInner::destroyData() { - sel = nullptr; + _sel = nullptr; _hashtagSel = -1; _hashtagResults.clear(); _filteredSel = -1; @@ -1453,6 +1576,9 @@ void DialogsInner::destroyData() { contacts = nullptr; contactsNoDialogs = nullptr; dialogs = nullptr; + if (importantDialogs) { + importantDialogs = nullptr; + } } void DialogsInner::peerBefore(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) const { @@ -1462,9 +1588,9 @@ void DialogsInner::peerBefore(const PeerData *inPeer, MsgId inMsg, PeerData *&ou return; } if (_state == DefaultState) { - if (auto row = dialogs->getRow(inPeer->id)) { - auto i = dialogs->cfind(row); - if (i != dialogs->cbegin()) { + if (auto row = shownDialogs()->getRow(inPeer->id)) { + auto i = shownDialogs()->cfind(row); + if (i != shownDialogs()->cbegin()) { outPeer = (*(--i))->history()->peer; outMsg = ShowAtUnreadMsgId; return; @@ -1536,9 +1662,9 @@ void DialogsInner::peerAfter(const PeerData *inPeer, MsgId inMsg, PeerData *&out return; } if (_state == DefaultState) { - if (auto row = dialogs->getRow(inPeer->id)) { - auto i = dialogs->cfind(row) + 1; - if (i != dialogs->cend()) { + if (auto row = shownDialogs()->getRow(inPeer->id)) { + auto i = shownDialogs()->cfind(row) + 1; + if (i != shownDialogs()->cend()) { outPeer = (*i)->history()->peer; outMsg = ShowAtUnreadMsgId; return; @@ -1697,19 +1823,19 @@ void DialogsWidget::activate() { } void DialogsWidget::createDialog(History *history) { - bool creating = !history->inChatList(); + bool creating = !history->inChatList(Dialogs::Mode::All); _inner.createDialog(history); if (creating && history->peer->migrateFrom()) { if (History *h = App::historyLoaded(history->peer->migrateFrom()->id)) { - if (h->inChatList()) { + if (h->inChatList(Dialogs::Mode::All)) { removeDialog(h); } } } } -void DialogsWidget::dlgUpdated(Dialogs::Row *row) { - _inner.dlgUpdated(row); +void DialogsWidget::dlgUpdated(Dialogs::Mode list, Dialogs::Row *row) { + _inner.dlgUpdated(list, row); } void DialogsWidget::dlgUpdated(History *row, MsgId msgId) { @@ -1795,6 +1921,10 @@ void DialogsWidget::notify_userIsContactChanged(UserData *user, bool fromThisApp _inner.notify_userIsContactChanged(user, fromThisApp); } +void DialogsWidget::notify_historyMuteUpdated(History *history) { + _inner.notify_historyMuteUpdated(history); +} + void DialogsWidget::unreadCountsReceived(const QVector<MTPDialog> &dialogs) { for (QVector<MTPDialog>::const_iterator i = dialogs.cbegin(), e = dialogs.cend(); i != e; ++i) { switch (i->type()) { @@ -1802,7 +1932,7 @@ void DialogsWidget::unreadCountsReceived(const QVector<MTPDialog> &dialogs) { const auto &d(i->c_dialog()); if (History *h = App::historyLoaded(peerFromMTP(d.vpeer))) { App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, h); - if (d.vunread_count.v >= h->unreadCount) { + if (d.vunread_count.v >= h->unreadCount()) { h->setUnreadCount(d.vunread_count.v, false); h->inboxReadBefore = d.vread_inbox_max_id.v + 1; } @@ -1820,7 +1950,7 @@ void DialogsWidget::unreadCountsReceived(const QVector<MTPDialog> &dialogs) { } App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, h); int32 unreadCount = h->isMegagroup() ? d.vunread_count.v : d.vunread_important_count.v; - if (unreadCount >= h->unreadCount) { + if (unreadCount >= h->unreadCount()) { h->setUnreadCount(unreadCount, false); h->inboxReadBefore = d.vread_inbox_max_id.v + 1; } diff --git a/Telegram/SourceFiles/dialogswidget.h b/Telegram/SourceFiles/dialogswidget.h index 4def9e106..fe5b33e62 100644 --- a/Telegram/SourceFiles/dialogswidget.h +++ b/Telegram/SourceFiles/dialogswidget.h @@ -54,10 +54,6 @@ public: void contactsReceived(const QVector<MTPContact> &contacts); - int32 filteredOffset() const; - int32 peopleOffset() const; - int32 searchedOffset() const; - void mouseMoveEvent(QMouseEvent *e); void mousePressEvent(QMouseEvent *e); void resizeEvent(QResizeEvent *e); @@ -65,14 +61,11 @@ public: void leaveEvent(QEvent *e); void contextMenuEvent(QContextMenuEvent *e); - void peopleResultPaint(PeerData *peer, Painter &p, int32 w, bool act, bool sel, bool onlyBackground) const; - void searchInPeerPaint(Painter &p, int32 w, bool onlyBackground) const; - void selectSkip(int32 direction); void selectSkipPage(int32 pixels, int32 direction); void createDialog(History *history); - void dlgUpdated(Dialogs::Row *row); + void dlgUpdated(Dialogs::Mode list, Dialogs::Row *row); void dlgUpdated(History *row, MsgId msgId); void removeDialog(History *history); @@ -125,6 +118,7 @@ public: void updateNotifySettings(PeerData *peer); void notify_userIsContactChanged(UserData *user, bool fromThisApp); + void notify_historyMuteUpdated(History *history); ~DialogsInner(); @@ -165,17 +159,34 @@ protected: private: + int dialogsOffset() const; + int filteredOffset() const; + int peopleOffset() const; + int searchedOffset() const; + + void peopleResultPaint(PeerData *peer, Painter &p, int32 w, bool active, bool selected, bool onlyBackground) const; + void searchInPeerPaint(Painter &p, int32 w, bool onlyBackground) const; + + void clearSelection(); void clearSearchResults(bool clearPeople = true); void updateSelectedRow(PeerData *peer = 0); bool menuPeerMuted(); void contextBlockDone(QPair<UserData*, bool> data, const MTPBool &result); + Dialogs::IndexedList *shownDialogs() const { + return (Global::DialogsMode() == Dialogs::Mode::Important) ? importantDialogs.get() : dialogs.get(); + } + using DialogsList = std_::unique_ptr<Dialogs::IndexedList>; DialogsList dialogs; + DialogsList importantDialogs; + DialogsList contactsNoDialogs; DialogsList contacts; - Dialogs::Row *sel = nullptr; - bool selByMouse = false; + + bool _importantSwitchSel = false; + Dialogs::Row *_sel = nullptr; + bool _selByMouse = false; QString _filter, _hashtagFilter; @@ -244,7 +255,7 @@ public: void loadDialogs(); void createDialog(History *history); - void dlgUpdated(Dialogs::Row *row); + void dlgUpdated(Dialogs::Mode list, Dialogs::Row *row); void dlgUpdated(History *row, MsgId msgId); void dialogsToUp(); @@ -276,6 +287,7 @@ public: } void notify_userIsContactChanged(UserData *user, bool fromThisApp); + void notify_historyMuteUpdated(History *history); signals: diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 252404416..fd74f4b6a 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -34,297 +34,301 @@ Q_DECLARE_METATYPE(Qt::MouseButton); namespace App { - void sendBotCommand(PeerData *peer, const QString &cmd, MsgId replyTo) { - if (MainWidget *m = main()) m->sendBotCommand(peer, cmd, replyTo); - } - - bool insertBotCommand(const QString &cmd, bool specialGif) { - if (MainWidget *m = main()) return m->insertBotCommand(cmd, specialGif); - return false; - } - - void activateBotCommand(const HistoryItem *msg, int row, int col) { - const HistoryMessageReplyMarkup::Button *button = nullptr; - if (auto markup = msg->Get<HistoryMessageReplyMarkup>()) { - if (row < markup->rows.size()) { - const auto &buttonRow(markup->rows.at(row)); - if (col < buttonRow.size()) { - button = &buttonRow.at(col); - } - } - } - if (!button) return; - - switch (button->type) { - case HistoryMessageReplyMarkup::Button::Default: { - // Copy string before passing it to the sending method - // because the original button can be destroyed inside. - MsgId replyTo = (msg->id > 0) ? msg->id : 0; - sendBotCommand(msg->history()->peer, QString(button->text), replyTo); - } break; - - case HistoryMessageReplyMarkup::Button::Callback: { - if (MainWidget *m = main()) { - m->app_sendBotCallback(button, msg, row, col); - } - } break; - - case HistoryMessageReplyMarkup::Button::Url: { - auto url = QString::fromUtf8(button->data); - HiddenUrlClickHandler(url).onClick(Qt::LeftButton); - } break; - - case HistoryMessageReplyMarkup::Button::RequestLocation: { - Ui::showLayer(new InformBox(lang(lng_bot_share_location_unavailable))); - } break; - - case HistoryMessageReplyMarkup::Button::RequestPhone: { - SharePhoneConfirmBox *box = new SharePhoneConfirmBox(msg->history()->peer); - box->connect(box, SIGNAL(confirmed(PeerData*)), App::main(), SLOT(onSharePhoneWithBot(PeerData*))); - Ui::showLayer(box); - } break; - - case HistoryMessageReplyMarkup::Button::SwitchInline: { - if (MainWidget *m = App::main()) { - if (UserData *bot = msg->history()->peer->asUser()) { - auto tryFastSwitch = [bot, &button]() -> bool { - if (bot->botInfo && bot->botInfo->inlineReturnPeerId) { - if (Notify::switchInlineBotButtonReceived(QString::fromUtf8(button->data))) { - return true; - } - } - return false; - }; - if (!tryFastSwitch()) { - m->inlineSwitchLayer('@' + bot->username + ' ' + QString::fromUtf8(button->data)); - } - } - } - } break; - } - } - - void searchByHashtag(const QString &tag, PeerData *inPeer) { - if (MainWidget *m = main()) m->searchMessages(tag + ' ', (inPeer && inPeer->isChannel() && !inPeer->isMegagroup()) ? inPeer : 0); - } - - void openPeerByName(const QString &username, MsgId msgId, const QString &startToken) { - if (MainWidget *m = main()) m->openPeerByName(username, msgId, startToken); - } - - void joinGroupByHash(const QString &hash) { - if (MainWidget *m = main()) m->joinGroupByHash(hash); - } - - void stickersBox(const QString &name) { - if (MainWidget *m = main()) m->stickersBox(MTP_inputStickerSetShortName(MTP_string(name))); - } - - void openLocalUrl(const QString &url) { - if (MainWidget *m = main()) m->openLocalUrl(url); - } - - bool forward(const PeerId &peer, ForwardWhatMessages what) { - if (MainWidget *m = main()) return m->onForward(peer, what); - return false; - } - - void removeDialog(History *history) { - if (MainWidget *m = main()) { - m->removeDialog(history); - } - } - - void showSettings() { - if (Window *w = wnd()) { - w->showSettings(); - } - } - - void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) { - if (Window *w = wnd()) { - qRegisterMetaType<ClickHandlerPtr>(); - qRegisterMetaType<Qt::MouseButton>(); - QMetaObject::invokeMethod(w, "app_activateClickHandler", Qt::QueuedConnection, Q_ARG(ClickHandlerPtr, handler), Q_ARG(Qt::MouseButton, button)); - } - } - - void logOutDelayed() { - if (Window *w = App::wnd()) { - QMetaObject::invokeMethod(w, "onLogoutSure", Qt::QueuedConnection); - } - } - +void sendBotCommand(PeerData *peer, const QString &cmd, MsgId replyTo) { + if (MainWidget *m = main()) m->sendBotCommand(peer, cmd, replyTo); } +bool insertBotCommand(const QString &cmd, bool specialGif) { + if (MainWidget *m = main()) return m->insertBotCommand(cmd, specialGif); + return false; +} + +void activateBotCommand(const HistoryItem *msg, int row, int col) { + const HistoryMessageReplyMarkup::Button *button = nullptr; + if (auto markup = msg->Get<HistoryMessageReplyMarkup>()) { + if (row < markup->rows.size()) { + const auto &buttonRow(markup->rows.at(row)); + if (col < buttonRow.size()) { + button = &buttonRow.at(col); + } + } + } + if (!button) return; + + switch (button->type) { + case HistoryMessageReplyMarkup::Button::Default: { + // Copy string before passing it to the sending method + // because the original button can be destroyed inside. + MsgId replyTo = (msg->id > 0) ? msg->id : 0; + sendBotCommand(msg->history()->peer, QString(button->text), replyTo); + } break; + + case HistoryMessageReplyMarkup::Button::Callback: { + if (MainWidget *m = main()) { + m->app_sendBotCallback(button, msg, row, col); + } + } break; + + case HistoryMessageReplyMarkup::Button::Url: { + auto url = QString::fromUtf8(button->data); + HiddenUrlClickHandler(url).onClick(Qt::LeftButton); + } break; + + case HistoryMessageReplyMarkup::Button::RequestLocation: { + Ui::showLayer(new InformBox(lang(lng_bot_share_location_unavailable))); + } break; + + case HistoryMessageReplyMarkup::Button::RequestPhone: { + SharePhoneConfirmBox *box = new SharePhoneConfirmBox(msg->history()->peer); + box->connect(box, SIGNAL(confirmed(PeerData*)), App::main(), SLOT(onSharePhoneWithBot(PeerData*))); + Ui::showLayer(box); + } break; + + case HistoryMessageReplyMarkup::Button::SwitchInline: { + if (MainWidget *m = App::main()) { + if (UserData *bot = msg->history()->peer->asUser()) { + auto tryFastSwitch = [bot, &button]() -> bool { + if (bot->botInfo && bot->botInfo->inlineReturnPeerId) { + if (Notify::switchInlineBotButtonReceived(QString::fromUtf8(button->data))) { + return true; + } + } + return false; + }; + if (!tryFastSwitch()) { + m->inlineSwitchLayer('@' + bot->username + ' ' + QString::fromUtf8(button->data)); + } + } + } + } break; + } +} + +void searchByHashtag(const QString &tag, PeerData *inPeer) { + if (MainWidget *m = main()) m->searchMessages(tag + ' ', (inPeer && inPeer->isChannel() && !inPeer->isMegagroup()) ? inPeer : 0); +} + +void openPeerByName(const QString &username, MsgId msgId, const QString &startToken) { + if (MainWidget *m = main()) m->openPeerByName(username, msgId, startToken); +} + +void joinGroupByHash(const QString &hash) { + if (MainWidget *m = main()) m->joinGroupByHash(hash); +} + +void stickersBox(const QString &name) { + if (MainWidget *m = main()) m->stickersBox(MTP_inputStickerSetShortName(MTP_string(name))); +} + +void openLocalUrl(const QString &url) { + if (MainWidget *m = main()) m->openLocalUrl(url); +} + +bool forward(const PeerId &peer, ForwardWhatMessages what) { + if (MainWidget *m = main()) return m->onForward(peer, what); + return false; +} + +void removeDialog(History *history) { + if (MainWidget *m = main()) { + m->removeDialog(history); + } +} + +void showSettings() { + if (Window *w = wnd()) { + w->showSettings(); + } +} + +void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) { + if (Window *w = wnd()) { + qRegisterMetaType<ClickHandlerPtr>(); + qRegisterMetaType<Qt::MouseButton>(); + QMetaObject::invokeMethod(w, "app_activateClickHandler", Qt::QueuedConnection, Q_ARG(ClickHandlerPtr, handler), Q_ARG(Qt::MouseButton, button)); + } +} + +void logOutDelayed() { + if (Window *w = App::wnd()) { + QMetaObject::invokeMethod(w, "onLogoutSure", Qt::QueuedConnection); + } +} + +} // namespace App + namespace Ui { - void showMediaPreview(DocumentData *document) { +void showMediaPreview(DocumentData *document) { + if (Window *w = App::wnd()) { + w->ui_showMediaPreview(document); + } +} + +void showMediaPreview(PhotoData *photo) { + if (Window *w = App::wnd()) { + w->ui_showMediaPreview(photo); + } +} + +void hideMediaPreview() { + if (Window *w = App::wnd()) { + w->ui_hideMediaPreview(); + } +} + +void showLayer(LayeredWidget *box, ShowLayerOptions options) { + if (Window *w = App::wnd()) { + w->ui_showLayer(box, options); + } else { + delete box; + } +} + +void hideLayer(bool fast) { + if (Window *w = App::wnd()) w->ui_showLayer(0, ShowLayerOptions(CloseOtherLayers) | (fast ? ForceFastShowLayer : AnimatedShowLayer)); +} + +bool isLayerShown() { + if (Window *w = App::wnd()) return w->ui_isLayerShown(); + return false; +} + +bool isMediaViewShown() { + if (Window *w = App::wnd()) return w->ui_isMediaViewShown(); + return false; +} + +bool isInlineItemBeingChosen() { + if (MainWidget *m = App::main()) return m->ui_isInlineItemBeingChosen(); + return false; +} + +void repaintHistoryItem(const HistoryItem *item) { + if (!item) return; + if (MainWidget *m = App::main()) m->ui_repaintHistoryItem(item); +} + +void repaintInlineItem(const InlineBots::Layout::ItemBase *layout) { + if (!layout) return; + if (MainWidget *m = App::main()) m->ui_repaintInlineItem(layout); +} + +bool isInlineItemVisible(const InlineBots::Layout::ItemBase *layout) { + if (MainWidget *m = App::main()) return m->ui_isInlineItemVisible(layout); + return false; +} + +void autoplayMediaInlineAsync(const FullMsgId &msgId) { + if (MainWidget *m = App::main()) { + QMetaObject::invokeMethod(m, "ui_autoplayMediaInlineAsync", Qt::QueuedConnection, Q_ARG(qint32, msgId.channel), Q_ARG(qint32, msgId.msg)); + } +} + +void showPeerHistory(const PeerId &peer, MsgId msgId, bool back) { + if (MainWidget *m = App::main()) m->ui_showPeerHistory(peer, msgId, back); +} + +void showPeerHistoryAsync(const PeerId &peer, MsgId msgId) { + if (MainWidget *m = App::main()) { + QMetaObject::invokeMethod(m, "ui_showPeerHistoryAsync", Qt::QueuedConnection, Q_ARG(quint64, peer), Q_ARG(qint32, msgId)); + } +} + +PeerData *getPeerForMouseAction() { + if (Window *w = App::wnd()) { + return w->ui_getPeerForMouseAction(); + } + return nullptr; +} + +bool hideWindowNoQuit() { + if (!App::quitting()) { if (Window *w = App::wnd()) { - w->ui_showMediaPreview(document); - } - } - - void showMediaPreview(PhotoData *photo) { - if (Window *w = App::wnd()) { - w->ui_showMediaPreview(photo); - } - } - - void hideMediaPreview() { - if (Window *w = App::wnd()) { - w->ui_hideMediaPreview(); - } - } - - void showLayer(LayeredWidget *box, ShowLayerOptions options) { - if (Window *w = App::wnd()) { - w->ui_showLayer(box, options); - } else { - delete box; - } - } - - void hideLayer(bool fast) { - if (Window *w = App::wnd()) w->ui_showLayer(0, ShowLayerOptions(CloseOtherLayers) | (fast ? ForceFastShowLayer : AnimatedShowLayer)); - } - - bool isLayerShown() { - if (Window *w = App::wnd()) return w->ui_isLayerShown(); - return false; - } - - bool isMediaViewShown() { - if (Window *w = App::wnd()) return w->ui_isMediaViewShown(); - return false; - } - - bool isInlineItemBeingChosen() { - if (MainWidget *m = App::main()) return m->ui_isInlineItemBeingChosen(); - return false; - } - - void repaintHistoryItem(const HistoryItem *item) { - if (!item) return; - if (MainWidget *m = App::main()) m->ui_repaintHistoryItem(item); - } - - void repaintInlineItem(const InlineBots::Layout::ItemBase *layout) { - if (!layout) return; - if (MainWidget *m = App::main()) m->ui_repaintInlineItem(layout); - } - - bool isInlineItemVisible(const InlineBots::Layout::ItemBase *layout) { - if (MainWidget *m = App::main()) return m->ui_isInlineItemVisible(layout); - return false; - } - - void autoplayMediaInlineAsync(const FullMsgId &msgId) { - if (MainWidget *m = App::main()) { - QMetaObject::invokeMethod(m, "ui_autoplayMediaInlineAsync", Qt::QueuedConnection, Q_ARG(qint32, msgId.channel), Q_ARG(qint32, msgId.msg)); - } - } - - void showPeerHistory(const PeerId &peer, MsgId msgId, bool back) { - if (MainWidget *m = App::main()) m->ui_showPeerHistory(peer, msgId, back); - } - - void showPeerHistoryAsync(const PeerId &peer, MsgId msgId) { - if (MainWidget *m = App::main()) { - QMetaObject::invokeMethod(m, "ui_showPeerHistoryAsync", Qt::QueuedConnection, Q_ARG(quint64, peer), Q_ARG(qint32, msgId)); - } - } - - PeerData *getPeerForMouseAction() { - if (Window *w = App::wnd()) { - return w->ui_getPeerForMouseAction(); - } - return nullptr; - } - - bool hideWindowNoQuit() { - if (!App::quitting()) { - if (Window *w = App::wnd()) { - if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) { - return w->minimizeToTray(); - } else if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) { - w->hide(); - w->updateIsActive(Global::OfflineBlurTimeout()); - w->updateGlobalMenu(); - return true; - } + if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) { + return w->minimizeToTray(); + } else if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) { + w->hide(); + w->updateIsActive(Global::OfflineBlurTimeout()); + w->updateGlobalMenu(); + return true; } } - return false; } - + return false; } +} // namespace Ui + namespace Notify { - void userIsBotChanged(UserData *user) { - if (MainWidget *m = App::main()) m->notify_userIsBotChanged(user); - } - - void userIsContactChanged(UserData *user, bool fromThisApp) { - if (MainWidget *m = App::main()) m->notify_userIsContactChanged(user, fromThisApp); - } - - void botCommandsChanged(UserData *user) { - if (MainWidget *m = App::main()) m->notify_botCommandsChanged(user); - } - - void inlineBotRequesting(bool requesting) { - if (MainWidget *m = App::main()) m->notify_inlineBotRequesting(requesting); - } - - void replyMarkupUpdated(const HistoryItem *item) { - if (MainWidget *m = App::main()) { - m->notify_replyMarkupUpdated(item); - } - } - - void inlineKeyboardMoved(const HistoryItem *item, int oldKeyboardTop, int newKeyboardTop) { - if (MainWidget *m = App::main()) { - m->notify_inlineKeyboardMoved(item, oldKeyboardTop, newKeyboardTop); - } - } - - bool switchInlineBotButtonReceived(const QString &query) { - if (MainWidget *m = App::main()) { - return m->notify_switchInlineBotButtonReceived(query); - } - return false; - } - - void migrateUpdated(PeerData *peer) { - if (MainWidget *m = App::main()) m->notify_migrateUpdated(peer); - } - - void clipStopperHidden(ClipStopperType type) { - if (MainWidget *m = App::main()) m->notify_clipStopperHidden(type); - } - - void historyItemLayoutChanged(const HistoryItem *item) { - if (MainWidget *m = App::main()) m->notify_historyItemLayoutChanged(item); - } - - void inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout) { - if (MainWidget *m = App::main()) m->notify_inlineItemLayoutChanged(layout); - } - - void handlePendingHistoryUpdate() { - if (MainWidget *m = App::main()) { - m->notify_handlePendingHistoryUpdate(); - } - for_const (HistoryItem *item, Global::PendingRepaintItems()) { - Ui::repaintHistoryItem(item); - } - Global::RefPendingRepaintItems().clear(); - } - +void userIsBotChanged(UserData *user) { + if (MainWidget *m = App::main()) m->notify_userIsBotChanged(user); } +void userIsContactChanged(UserData *user, bool fromThisApp) { + if (MainWidget *m = App::main()) m->notify_userIsContactChanged(user, fromThisApp); +} + +void botCommandsChanged(UserData *user) { + if (MainWidget *m = App::main()) m->notify_botCommandsChanged(user); +} + +void inlineBotRequesting(bool requesting) { + if (MainWidget *m = App::main()) m->notify_inlineBotRequesting(requesting); +} + +void replyMarkupUpdated(const HistoryItem *item) { + if (MainWidget *m = App::main()) { + m->notify_replyMarkupUpdated(item); + } +} + +void inlineKeyboardMoved(const HistoryItem *item, int oldKeyboardTop, int newKeyboardTop) { + if (MainWidget *m = App::main()) { + m->notify_inlineKeyboardMoved(item, oldKeyboardTop, newKeyboardTop); + } +} + +bool switchInlineBotButtonReceived(const QString &query) { + if (MainWidget *m = App::main()) { + return m->notify_switchInlineBotButtonReceived(query); + } + return false; +} + +void migrateUpdated(PeerData *peer) { + if (MainWidget *m = App::main()) m->notify_migrateUpdated(peer); +} + +void clipStopperHidden(ClipStopperType type) { + if (MainWidget *m = App::main()) m->notify_clipStopperHidden(type); +} + +void historyItemLayoutChanged(const HistoryItem *item) { + if (MainWidget *m = App::main()) m->notify_historyItemLayoutChanged(item); +} + +void inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout) { + if (MainWidget *m = App::main()) m->notify_inlineItemLayoutChanged(layout); +} + +void historyMuteUpdated(History *history) { + if (MainWidget *m = App::main()) m->notify_historyMuteUpdated(history); +} + +void handlePendingHistoryUpdate() { + if (MainWidget *m = App::main()) { + m->notify_handlePendingHistoryUpdate(); + } + for_const (HistoryItem *item, Global::PendingRepaintItems()) { + Ui::repaintHistoryItem(item); + } + Global::RefPendingRepaintItems().clear(); +} + +} // namespace Notify + #define DefineReadOnlyVar(Namespace, Type, Name) const Type &Name() { \ t_assert_full(Namespace##Data != 0, #Namespace "Data != nullptr in " #Namespace "::" #Name, __FILE__, __LINE__); \ return Namespace##Data->Name; \ @@ -341,235 +345,238 @@ void Set##Name(const Type &Name) { \ } namespace Sandbox { +namespace internal { - namespace internal { +struct Data { + QString LangSystemISO; + int32 LangSystem = languageDefault; - struct Data { - QString LangSystemISO; - int32 LangSystem = languageDefault; + QByteArray LastCrashDump; + ConnectionProxy PreLaunchProxy; +}; - QByteArray LastCrashDump; - ConnectionProxy PreLaunchProxy; - }; +} // namespace internal +} // namespace Sandbox - } - -} -Sandbox::internal::Data *SandboxData = 0; +Sandbox::internal::Data *SandboxData = nullptr; uint64 SandboxUserTag = 0; namespace Sandbox { - bool CheckBetaVersionDir() { - QFile beta(cExeDir() + qsl("TelegramBeta_data/tdata/beta")); - if (cBetaVersion()) { - cForceWorkingDir(cExeDir() + qsl("TelegramBeta_data/")); - QDir().mkpath(cWorkingDir() + qstr("tdata")); - if (*BetaPrivateKey) { - cSetBetaPrivateKey(QByteArray(BetaPrivateKey)); - } - if (beta.open(QIODevice::WriteOnly)) { - QDataStream dataStream(&beta); - dataStream.setVersion(QDataStream::Qt_5_3); - dataStream << quint64(cRealBetaVersion()) << cBetaPrivateKey(); - } else { - LOG(("FATAL: Could not open '%1' for writing private key!").arg(beta.fileName())); - return false; - } - } else if (beta.exists()) { - cForceWorkingDir(cExeDir() + qsl("TelegramBeta_data/")); - if (beta.open(QIODevice::ReadOnly)) { - QDataStream dataStream(&beta); - dataStream.setVersion(QDataStream::Qt_5_3); - - quint64 v; - QByteArray k; - dataStream >> v >> k; - if (dataStream.status() == QDataStream::Ok) { - cSetBetaVersion(qMax(v, AppVersion * 1000ULL)); - cSetBetaPrivateKey(k); - cSetRealBetaVersion(v); - } else { - LOG(("FATAL: '%1' is corrupted, reinstall private beta!").arg(beta.fileName())); - return false; - } - } else { - LOG(("FATAL: could not open '%1' for reading private key!").arg(beta.fileName())); - return false; - } +bool CheckBetaVersionDir() { + QFile beta(cExeDir() + qsl("TelegramBeta_data/tdata/beta")); + if (cBetaVersion()) { + cForceWorkingDir(cExeDir() + qsl("TelegramBeta_data/")); + QDir().mkpath(cWorkingDir() + qstr("tdata")); + if (*BetaPrivateKey) { + cSetBetaPrivateKey(QByteArray(BetaPrivateKey)); + } + if (beta.open(QIODevice::WriteOnly)) { + QDataStream dataStream(&beta); + dataStream.setVersion(QDataStream::Qt_5_3); + dataStream << quint64(cRealBetaVersion()) << cBetaPrivateKey(); + } else { + LOG(("FATAL: Could not open '%1' for writing private key!").arg(beta.fileName())); + return false; + } + } else if (beta.exists()) { + cForceWorkingDir(cExeDir() + qsl("TelegramBeta_data/")); + if (beta.open(QIODevice::ReadOnly)) { + QDataStream dataStream(&beta); + dataStream.setVersion(QDataStream::Qt_5_3); + + quint64 v; + QByteArray k; + dataStream >> v >> k; + if (dataStream.status() == QDataStream::Ok) { + cSetBetaVersion(qMax(v, AppVersion * 1000ULL)); + cSetBetaPrivateKey(k); + cSetRealBetaVersion(v); + } else { + LOG(("FATAL: '%1' is corrupted, reinstall private beta!").arg(beta.fileName())); + return false; + } + } else { + LOG(("FATAL: could not open '%1' for reading private key!").arg(beta.fileName())); + return false; + } + } + return true; +} + +void WorkingDirReady() { + if (QFile(cWorkingDir() + qsl("tdata/withtestmode")).exists()) { + cSetTestMode(true); + } + if (!cDebug() && QFile(cWorkingDir() + qsl("tdata/withdebug")).exists()) { + cSetDebug(true); + } + if (cBetaVersion()) { + cSetDevVersion(false); + } else if (!cDevVersion() && QFile(cWorkingDir() + qsl("tdata/devversion")).exists()) { + cSetDevVersion(true); + } else if (DevVersion) { + QFile f(cWorkingDir() + qsl("tdata/devversion")); + if (!f.exists() && f.open(QIODevice::WriteOnly)) { + f.write("1"); } - return true; } - void WorkingDirReady() { - if (QFile(cWorkingDir() + qsl("tdata/withtestmode")).exists()) { - cSetTestMode(true); - } - if (!cDebug() && QFile(cWorkingDir() + qsl("tdata/withdebug")).exists()) { - cSetDebug(true); - } - if (cBetaVersion()) { - cSetDevVersion(false); - } else if (!cDevVersion() && QFile(cWorkingDir() + qsl("tdata/devversion")).exists()) { - cSetDevVersion(true); - } else if (DevVersion) { - QFile f(cWorkingDir() + qsl("tdata/devversion")); - if (!f.exists() && f.open(QIODevice::WriteOnly)) { - f.write("1"); - } - } + srand((int32)time(NULL)); - srand((int32)time(NULL)); + SandboxUserTag = 0; + QFile usertag(cWorkingDir() + qsl("tdata/usertag")); + if (usertag.open(QIODevice::ReadOnly)) { + if (usertag.read(reinterpret_cast<char*>(&SandboxUserTag), sizeof(uint64)) != sizeof(uint64)) { + SandboxUserTag = 0; + } + usertag.close(); + } + if (!SandboxUserTag) { + do { + memsetrnd_bad(SandboxUserTag); + } while (!SandboxUserTag); - SandboxUserTag = 0; - QFile usertag(cWorkingDir() + qsl("tdata/usertag")); - if (usertag.open(QIODevice::ReadOnly)) { - if (usertag.read(reinterpret_cast<char*>(&SandboxUserTag), sizeof(uint64)) != sizeof(uint64)) { - SandboxUserTag = 0; - } + if (usertag.open(QIODevice::WriteOnly)) { + usertag.write(reinterpret_cast<char*>(&SandboxUserTag), sizeof(uint64)); usertag.close(); } - if (!SandboxUserTag) { - do { - memsetrnd_bad(SandboxUserTag); - } while (!SandboxUserTag); - - if (usertag.open(QIODevice::WriteOnly)) { - usertag.write(reinterpret_cast<char*>(&SandboxUserTag), sizeof(uint64)); - usertag.close(); - } - } - } - - void start() { - SandboxData = new internal::Data(); - - SandboxData->LangSystemISO = psCurrentLanguage(); - if (SandboxData->LangSystemISO.isEmpty()) SandboxData->LangSystemISO = qstr("en"); - QByteArray l = LangSystemISO().toLatin1(); - for (int32 i = 0; i < languageCount; ++i) { - if (l.at(0) == LanguageCodes[i][0] && l.at(1) == LanguageCodes[i][1]) { - SandboxData->LangSystem = i; - break; - } - } - } - - void finish() { - delete SandboxData; - SandboxData = 0; - } - - uint64 UserTag() { - return SandboxUserTag; - } - - DefineReadOnlyVar(Sandbox, QString, LangSystemISO); - DefineReadOnlyVar(Sandbox, int32, LangSystem); - DefineVar(Sandbox, QByteArray, LastCrashDump); - DefineVar(Sandbox, ConnectionProxy, PreLaunchProxy); - -} - -namespace Global { - namespace internal { - - struct Data { - uint64 LaunchId = 0; - SingleDelayedCall HandleHistoryUpdate = { App::app(), "call_handleHistoryUpdate" }; - - Adaptive::Layout AdaptiveLayout = Adaptive::NormalLayout; - bool AdaptiveForWide = true; - - int32 DebugLoggingFlags = 0; - - // config - int32 ChatSizeMax = 200; - int32 MegagroupSizeMax = 1000; - int32 ForwardedCountMax = 100; - int32 OnlineUpdatePeriod = 120000; - int32 OfflineBlurTimeout = 5000; - int32 OfflineIdleTimeout = 30000; - int32 OnlineFocusTimeout = 1000; - int32 OnlineCloudTimeout = 300000; - int32 NotifyCloudDelay = 30000; - int32 NotifyDefaultDelay = 1500; - int32 ChatBigSize = 10; - int32 PushChatPeriod = 60000; - int32 PushChatLimit = 2; - int32 SavedGifsLimit = 200; - int32 EditTimeLimit = 172800; - - HiddenPinnedMessagesMap HiddenPinnedMessages; - - PendingItemsMap PendingRepaintItems; - - Stickers::Sets StickerSets; - Stickers::Order StickerSetsOrder; - uint64 LastStickersUpdate = 0; - - MTP::DcOptions DcOptions; - - CircleMasksMap CircleMasks; - }; - } } -Global::internal::Data *GlobalData = 0; +void start() { + SandboxData = new internal::Data(); + + SandboxData->LangSystemISO = psCurrentLanguage(); + if (SandboxData->LangSystemISO.isEmpty()) SandboxData->LangSystemISO = qstr("en"); + QByteArray l = LangSystemISO().toLatin1(); + for (int32 i = 0; i < languageCount; ++i) { + if (l.at(0) == LanguageCodes[i][0] && l.at(1) == LanguageCodes[i][1]) { + SandboxData->LangSystem = i; + break; + } + } +} + +void finish() { + delete SandboxData; + SandboxData = 0; +} + +uint64 UserTag() { + return SandboxUserTag; +} + +DefineReadOnlyVar(Sandbox, QString, LangSystemISO); +DefineReadOnlyVar(Sandbox, int32, LangSystem); +DefineVar(Sandbox, QByteArray, LastCrashDump); +DefineVar(Sandbox, ConnectionProxy, PreLaunchProxy); + +} // namespace Sandbox namespace Global { +namespace internal { - bool started() { - return GlobalData != 0; - } +struct Data { + uint64 LaunchId = 0; + SingleDelayedCall HandleHistoryUpdate = { App::app(), "call_handleHistoryUpdate" }; - void start() { - GlobalData = new internal::Data(); + Adaptive::Layout AdaptiveLayout = Adaptive::NormalLayout; + bool AdaptiveForWide = true; + bool DialogsModeEnabled = false; + Dialogs::Mode DialogsMode = Dialogs::Mode::All; - memset_rand(&GlobalData->LaunchId, sizeof(GlobalData->LaunchId)); - } - - void finish() { - delete GlobalData; - GlobalData = 0; - } - - DefineReadOnlyVar(Global, uint64, LaunchId); - DefineRefVar(Global, SingleDelayedCall, HandleHistoryUpdate); - - DefineVar(Global, Adaptive::Layout, AdaptiveLayout); - DefineVar(Global, bool, AdaptiveForWide); - - DefineVar(Global, int32, DebugLoggingFlags); + int32 DebugLoggingFlags = 0; // config - DefineVar(Global, int32, ChatSizeMax); - DefineVar(Global, int32, MegagroupSizeMax); - DefineVar(Global, int32, ForwardedCountMax); - DefineVar(Global, int32, OnlineUpdatePeriod); - DefineVar(Global, int32, OfflineBlurTimeout); - DefineVar(Global, int32, OfflineIdleTimeout); - DefineVar(Global, int32, OnlineFocusTimeout); - DefineVar(Global, int32, OnlineCloudTimeout); - DefineVar(Global, int32, NotifyCloudDelay); - DefineVar(Global, int32, NotifyDefaultDelay); - DefineVar(Global, int32, ChatBigSize); - DefineVar(Global, int32, PushChatPeriod); - DefineVar(Global, int32, PushChatLimit); - DefineVar(Global, int32, SavedGifsLimit); - DefineVar(Global, int32, EditTimeLimit); + int32 ChatSizeMax = 200; + int32 MegagroupSizeMax = 1000; + int32 ForwardedCountMax = 100; + int32 OnlineUpdatePeriod = 120000; + int32 OfflineBlurTimeout = 5000; + int32 OfflineIdleTimeout = 30000; + int32 OnlineFocusTimeout = 1000; + int32 OnlineCloudTimeout = 300000; + int32 NotifyCloudDelay = 30000; + int32 NotifyDefaultDelay = 1500; + int32 ChatBigSize = 10; + int32 PushChatPeriod = 60000; + int32 PushChatLimit = 2; + int32 SavedGifsLimit = 200; + int32 EditTimeLimit = 172800; - DefineVar(Global, HiddenPinnedMessagesMap, HiddenPinnedMessages); + HiddenPinnedMessagesMap HiddenPinnedMessages; - DefineRefVar(Global, PendingItemsMap, PendingRepaintItems); + PendingItemsMap PendingRepaintItems; - DefineVar(Global, Stickers::Sets, StickerSets); - DefineVar(Global, Stickers::Order, StickerSetsOrder); - DefineVar(Global, uint64, LastStickersUpdate); + Stickers::Sets StickerSets; + Stickers::Order StickerSetsOrder; + uint64 LastStickersUpdate = 0; - DefineVar(Global, MTP::DcOptions, DcOptions); - - DefineRefVar(Global, CircleMasksMap, CircleMasks); + MTP::DcOptions DcOptions; + CircleMasksMap CircleMasks; }; + +} // namespace internal +} // namespace Global + +Global::internal::Data *GlobalData = nullptr; + +namespace Global { + +bool started() { + return GlobalData != nullptr; +} + +void start() { + GlobalData = new internal::Data(); + + memset_rand(&GlobalData->LaunchId, sizeof(GlobalData->LaunchId)); +} + +void finish() { + delete GlobalData; + GlobalData = nullptr; +} + +DefineReadOnlyVar(Global, uint64, LaunchId); +DefineRefVar(Global, SingleDelayedCall, HandleHistoryUpdate); + +DefineVar(Global, Adaptive::Layout, AdaptiveLayout); +DefineVar(Global, bool, AdaptiveForWide); +DefineVar(Global, bool, DialogsModeEnabled); +DefineVar(Global, Dialogs::Mode, DialogsMode); + +DefineVar(Global, int32, DebugLoggingFlags); + +// config +DefineVar(Global, int32, ChatSizeMax); +DefineVar(Global, int32, MegagroupSizeMax); +DefineVar(Global, int32, ForwardedCountMax); +DefineVar(Global, int32, OnlineUpdatePeriod); +DefineVar(Global, int32, OfflineBlurTimeout); +DefineVar(Global, int32, OfflineIdleTimeout); +DefineVar(Global, int32, OnlineFocusTimeout); +DefineVar(Global, int32, OnlineCloudTimeout); +DefineVar(Global, int32, NotifyCloudDelay); +DefineVar(Global, int32, NotifyDefaultDelay); +DefineVar(Global, int32, ChatBigSize); +DefineVar(Global, int32, PushChatPeriod); +DefineVar(Global, int32, PushChatLimit); +DefineVar(Global, int32, SavedGifsLimit); +DefineVar(Global, int32, EditTimeLimit); + +DefineVar(Global, HiddenPinnedMessagesMap, HiddenPinnedMessages); + +DefineRefVar(Global, PendingItemsMap, PendingRepaintItems); + +DefineVar(Global, Stickers::Sets, StickerSets); +DefineVar(Global, Stickers::Order, StickerSetsOrder); +DefineVar(Global, uint64, LastStickersUpdate); + +DefineVar(Global, MTP::DcOptions, DcOptions); + +DefineRefVar(Global, CircleMasksMap, CircleMasks); + +} // namespace Global diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 7888b8c64..a8bf6fbb1 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -24,23 +24,23 @@ class LayeredWidget; namespace App { - void sendBotCommand(PeerData *peer, const QString &cmd, MsgId replyTo = 0); - bool insertBotCommand(const QString &cmd, bool specialGif = false); - void activateBotCommand(const HistoryItem *msg, int row, int col); - void searchByHashtag(const QString &tag, PeerData *inPeer); - void openPeerByName(const QString &username, MsgId msgId = ShowAtUnreadMsgId, const QString &startToken = QString()); - void joinGroupByHash(const QString &hash); - void stickersBox(const QString &name); - void openLocalUrl(const QString &url); - bool forward(const PeerId &peer, ForwardWhatMessages what); - void removeDialog(History *history); - void showSettings(); +void sendBotCommand(PeerData *peer, const QString &cmd, MsgId replyTo = 0); +bool insertBotCommand(const QString &cmd, bool specialGif = false); +void activateBotCommand(const HistoryItem *msg, int row, int col); +void searchByHashtag(const QString &tag, PeerData *inPeer); +void openPeerByName(const QString &username, MsgId msgId = ShowAtUnreadMsgId, const QString &startToken = QString()); +void joinGroupByHash(const QString &hash); +void stickersBox(const QString &name); +void openLocalUrl(const QString &url); +bool forward(const PeerId &peer, ForwardWhatMessages what); +void removeDialog(History *history); +void showSettings(); - void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button); +void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button); - void logOutDelayed(); +void logOutDelayed(); -}; +} // namespace App namespace InlineBots { namespace Layout { @@ -52,43 +52,43 @@ class ItemBase; namespace Ui { - void showMediaPreview(DocumentData *document); - void showMediaPreview(PhotoData *photo); - void hideMediaPreview(); +void showMediaPreview(DocumentData *document); +void showMediaPreview(PhotoData *photo); +void hideMediaPreview(); - void showLayer(LayeredWidget *box, ShowLayerOptions options = CloseOtherLayers); - void hideLayer(bool fast = false); - bool isLayerShown(); - bool isMediaViewShown(); - bool isInlineItemBeingChosen(); +void showLayer(LayeredWidget *box, ShowLayerOptions options = CloseOtherLayers); +void hideLayer(bool fast = false); +bool isLayerShown(); +bool isMediaViewShown(); +bool isInlineItemBeingChosen(); - void repaintHistoryItem(const HistoryItem *item); - void repaintInlineItem(const InlineBots::Layout::ItemBase *layout); - bool isInlineItemVisible(const InlineBots::Layout::ItemBase *reader); - void autoplayMediaInlineAsync(const FullMsgId &msgId); +void repaintHistoryItem(const HistoryItem *item); +void repaintInlineItem(const InlineBots::Layout::ItemBase *layout); +bool isInlineItemVisible(const InlineBots::Layout::ItemBase *reader); +void autoplayMediaInlineAsync(const FullMsgId &msgId); - void showPeerHistory(const PeerId &peer, MsgId msgId, bool back = false); - inline void showPeerHistory(const PeerData *peer, MsgId msgId, bool back = false) { - showPeerHistory(peer->id, msgId, back); - } - inline void showPeerHistory(const History *history, MsgId msgId, bool back = false) { - showPeerHistory(history->peer->id, msgId, back); - } - inline void showPeerHistoryAtItem(const HistoryItem *item) { - showPeerHistory(item->history()->peer->id, item->id); - } - void showPeerHistoryAsync(const PeerId &peer, MsgId msgId); - inline void showChatsList() { - showPeerHistory(PeerId(0), 0); - } - inline void showChatsListAsync() { - showPeerHistoryAsync(PeerId(0), 0); - } - PeerData *getPeerForMouseAction(); +void showPeerHistory(const PeerId &peer, MsgId msgId, bool back = false); +inline void showPeerHistory(const PeerData *peer, MsgId msgId, bool back = false) { + showPeerHistory(peer->id, msgId, back); +} +inline void showPeerHistory(const History *history, MsgId msgId, bool back = false) { + showPeerHistory(history->peer->id, msgId, back); +} +inline void showPeerHistoryAtItem(const HistoryItem *item) { + showPeerHistory(item->history()->peer->id, item->id); +} +void showPeerHistoryAsync(const PeerId &peer, MsgId msgId); +inline void showChatsList() { + showPeerHistory(PeerId(0), 0); +} +inline void showChatsListAsync() { + showPeerHistoryAsync(PeerId(0), 0); +} +PeerData *getPeerForMouseAction(); - bool hideWindowNoQuit(); +bool hideWindowNoQuit(); -}; +} // namespace Ui enum ClipStopperType { ClipStopperMediaview, @@ -97,26 +97,27 @@ enum ClipStopperType { namespace Notify { - void userIsBotChanged(UserData *user); - void userIsContactChanged(UserData *user, bool fromThisApp = false); - void botCommandsChanged(UserData *user); +void userIsBotChanged(UserData *user); +void userIsContactChanged(UserData *user, bool fromThisApp = false); +void botCommandsChanged(UserData *user); - void inlineBotRequesting(bool requesting); - void replyMarkupUpdated(const HistoryItem *item); - void inlineKeyboardMoved(const HistoryItem *item, int oldKeyboardTop, int newKeyboardTop); - bool switchInlineBotButtonReceived(const QString &query); +void inlineBotRequesting(bool requesting); +void replyMarkupUpdated(const HistoryItem *item); +void inlineKeyboardMoved(const HistoryItem *item, int oldKeyboardTop, int newKeyboardTop); +bool switchInlineBotButtonReceived(const QString &query); - void migrateUpdated(PeerData *peer); +void migrateUpdated(PeerData *peer); - void clipStopperHidden(ClipStopperType type); +void clipStopperHidden(ClipStopperType type); - void historyItemLayoutChanged(const HistoryItem *item); - void inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout); +void historyItemLayoutChanged(const HistoryItem *item); +void inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout); +void historyMuteUpdated(History *history); - // handle pending resize() / paint() on history items - void handlePendingHistoryUpdate(); +// handle pending resize() / paint() on history items +void handlePendingHistoryUpdate(); -}; +} // namespace Notify #define DeclareReadOnlyVar(Type, Name) const Type &Name(); #define DeclareRefVar(Type, Name) DeclareReadOnlyVar(Type, Name) \ @@ -126,115 +127,123 @@ namespace Notify { namespace Sandbox { - bool CheckBetaVersionDir(); - void WorkingDirReady(); +bool CheckBetaVersionDir(); +void WorkingDirReady(); - void start(); - void finish(); +void start(); +void finish(); - uint64 UserTag(); +uint64 UserTag(); - DeclareReadOnlyVar(QString, LangSystemISO); - DeclareReadOnlyVar(int32, LangSystem); - DeclareVar(QByteArray, LastCrashDump); - DeclareVar(ConnectionProxy, PreLaunchProxy); +DeclareReadOnlyVar(QString, LangSystemISO); +DeclareReadOnlyVar(int32, LangSystem); +DeclareVar(QByteArray, LastCrashDump); +DeclareVar(ConnectionProxy, PreLaunchProxy); -} +} // namespace Sandbox namespace Adaptive { - enum Layout { - OneColumnLayout, - NormalLayout, - WideLayout, - }; +enum Layout { + OneColumnLayout, + NormalLayout, + WideLayout, }; +} // namespace Adaptive namespace DebugLogging { - enum Flags { - FileLoaderFlag = 0x00000001, - }; -} +enum Flags { + FileLoaderFlag = 0x00000001, +}; +} // namespace DebugLogging namespace Stickers { - static const uint64 DefaultSetId = 0; // for backward compatibility - static const uint64 CustomSetId = 0xFFFFFFFFFFFFFFFFULL, RecentSetId = 0xFFFFFFFFFFFFFFFEULL; - static const uint64 NoneSetId = 0xFFFFFFFFFFFFFFFDULL; // for emoji/stickers panel - struct Set { - Set(uint64 id, uint64 access, const QString &title, const QString &shortName, int32 count, int32 hash, MTPDstickerSet::Flags flags) : id(id), access(access), title(title), shortName(shortName), count(count), hash(hash), flags(flags) { - } - uint64 id, access; - QString title, shortName; - int32 count, hash; - MTPDstickerSet::Flags flags; - StickerPack stickers; - StickersByEmojiMap emoji; - }; - typedef QMap<uint64, Set> Sets; - typedef QList<uint64> Order; -} + +static const uint64 DefaultSetId = 0; // for backward compatibility +static const uint64 CustomSetId = 0xFFFFFFFFFFFFFFFFULL, RecentSetId = 0xFFFFFFFFFFFFFFFEULL; +static const uint64 NoneSetId = 0xFFFFFFFFFFFFFFFDULL; // for emoji/stickers panel +struct Set { + Set(uint64 id, uint64 access, const QString &title, const QString &shortName, int32 count, int32 hash, MTPDstickerSet::Flags flags) : id(id), access(access), title(title), shortName(shortName), count(count), hash(hash), flags(flags) { + } + uint64 id, access; + QString title, shortName; + int32 count, hash; + MTPDstickerSet::Flags flags; + StickerPack stickers; + StickersByEmojiMap emoji; +}; +using Sets = QMap<uint64, Set>; +using Order = QList<uint64>; + +} // namespace Stickers namespace Global { - bool started(); - void start(); - void finish(); +bool started(); +void start(); +void finish(); - DeclareReadOnlyVar(uint64, LaunchId); - DeclareRefVar(SingleDelayedCall, HandleHistoryUpdate); +DeclareReadOnlyVar(uint64, LaunchId); +DeclareRefVar(SingleDelayedCall, HandleHistoryUpdate); - DeclareVar(Adaptive::Layout, AdaptiveLayout); - DeclareVar(bool, AdaptiveForWide); +DeclareVar(Adaptive::Layout, AdaptiveLayout); +DeclareVar(bool, AdaptiveForWide); +DeclareVar(bool, DialogsModeEnabled); +DeclareVar(Dialogs::Mode, DialogsMode); - DeclareVar(int32, DebugLoggingFlags); +DeclareVar(int32, DebugLoggingFlags); - // config - DeclareVar(int32, ChatSizeMax); - DeclareVar(int32, MegagroupSizeMax); - DeclareVar(int32, ForwardedCountMax); - DeclareVar(int32, OnlineUpdatePeriod); - DeclareVar(int32, OfflineBlurTimeout); - DeclareVar(int32, OfflineIdleTimeout); - DeclareVar(int32, OnlineFocusTimeout); // not from config - DeclareVar(int32, OnlineCloudTimeout); - DeclareVar(int32, NotifyCloudDelay); - DeclareVar(int32, NotifyDefaultDelay); - DeclareVar(int32, ChatBigSize); - DeclareVar(int32, PushChatPeriod); - DeclareVar(int32, PushChatLimit); - DeclareVar(int32, SavedGifsLimit); - DeclareVar(int32, EditTimeLimit); +// config +DeclareVar(int32, ChatSizeMax); +DeclareVar(int32, MegagroupSizeMax); +DeclareVar(int32, ForwardedCountMax); +DeclareVar(int32, OnlineUpdatePeriod); +DeclareVar(int32, OfflineBlurTimeout); +DeclareVar(int32, OfflineIdleTimeout); +DeclareVar(int32, OnlineFocusTimeout); // not from config +DeclareVar(int32, OnlineCloudTimeout); +DeclareVar(int32, NotifyCloudDelay); +DeclareVar(int32, NotifyDefaultDelay); +DeclareVar(int32, ChatBigSize); +DeclareVar(int32, PushChatPeriod); +DeclareVar(int32, PushChatLimit); +DeclareVar(int32, SavedGifsLimit); +DeclareVar(int32, EditTimeLimit); - typedef QMap<PeerId, MsgId> HiddenPinnedMessagesMap; - DeclareVar(HiddenPinnedMessagesMap, HiddenPinnedMessages); +typedef QMap<PeerId, MsgId> HiddenPinnedMessagesMap; +DeclareVar(HiddenPinnedMessagesMap, HiddenPinnedMessages); - typedef OrderedSet<HistoryItem*> PendingItemsMap; - DeclareRefVar(PendingItemsMap, PendingRepaintItems); +typedef OrderedSet<HistoryItem*> PendingItemsMap; +DeclareRefVar(PendingItemsMap, PendingRepaintItems); - DeclareVar(Stickers::Sets, StickerSets); - DeclareVar(Stickers::Order, StickerSetsOrder); - DeclareVar(uint64, LastStickersUpdate); +DeclareVar(Stickers::Sets, StickerSets); +DeclareVar(Stickers::Order, StickerSetsOrder); +DeclareVar(uint64, LastStickersUpdate); - DeclareVar(MTP::DcOptions, DcOptions); +DeclareVar(MTP::DcOptions, DcOptions); - typedef QMap<uint64, QPixmap> CircleMasksMap; - DeclareRefVar(CircleMasksMap, CircleMasks); +typedef QMap<uint64, QPixmap> CircleMasksMap; +DeclareRefVar(CircleMasksMap, CircleMasks); -}; +} // namespace Global namespace Adaptive { - inline bool OneColumn() { - return Global::AdaptiveLayout() == OneColumnLayout; - } - inline bool Normal() { - return Global::AdaptiveLayout() == NormalLayout; - } - inline bool Wide() { - return Global::AdaptiveForWide() && (Global::AdaptiveLayout() == WideLayout); - } + +inline bool OneColumn() { + return Global::AdaptiveLayout() == OneColumnLayout; +} +inline bool Normal() { + return Global::AdaptiveLayout() == NormalLayout; +} +inline bool Wide() { + return Global::AdaptiveForWide() && (Global::AdaptiveLayout() == WideLayout); } +} // namespace Adaptive + namespace DebugLogging { - inline bool FileLoader() { - return (Global::DebugLoggingFlags() | FileLoaderFlag) != 0; - } + +inline bool FileLoader() { + return (Global::DebugLoggingFlags() | FileLoaderFlag) != 0; } + +} // namespace DebugLogging diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index cc987fb09..ef44e65bf 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -104,7 +104,7 @@ void historyInit() { History::History(const PeerId &peerId) : peer(App::peer(peerId)) -, mute(isNotifyMuted(peer->notify)) { +, _mute(isNotifyMuted(peer->notify)) { if (peer->isChannel() || (peer->isUser() && peer->asUser()->botInfo)) { outboxReadBefore = INT_MAX; } @@ -1683,7 +1683,7 @@ void History::updateShowFrom() { MsgId History::inboxRead(MsgId upTo) { if (upTo < 0) return upTo; - if (unreadCount) { + if (unreadCount()) { if (upTo && loadedAtBottom()) App::main()->historyToDown(this); setUnreadCount(upTo ? countUnread(upTo) : 0); } @@ -1739,7 +1739,7 @@ HistoryItem *History::lastImportantMessage() const { } void History::setUnreadCount(int newUnreadCount, bool psUpdate) { - if (unreadCount != newUnreadCount) { + if (_unreadCount != newUnreadCount) { if (newUnreadCount == 1) { if (loadedAtBottom()) showFrom = lastImportantMessage(); inboxReadBefore = qMax(inboxReadBefore, msgIdForRead()); @@ -1747,18 +1747,18 @@ void History::setUnreadCount(int newUnreadCount, bool psUpdate) { showFrom = nullptr; inboxReadBefore = qMax(inboxReadBefore, msgIdForRead() + 1); } - if (inChatList()) { - App::histories().unreadIncrement(newUnreadCount - unreadCount, mute); - if (psUpdate && (!mute || cIncludeMuted()) && App::wnd()) { + if (inChatList(Dialogs::Mode::All)) { + App::histories().unreadIncrement(newUnreadCount - _unreadCount, mute()); + if (psUpdate && (!mute() || cIncludeMuted()) && App::wnd()) { App::wnd()->updateCounter(); } } - unreadCount = newUnreadCount; + _unreadCount = newUnreadCount; if (unreadBar) { - int32 count = unreadCount; + int32 count = _unreadCount; if (peer->migrateTo()) { if (History *h = App::historyLoaded(peer->migrateTo()->id)) { - count += h->unreadCount; + count += h->unreadCount(); } } if (count > 0) { @@ -1771,11 +1771,14 @@ void History::setUnreadCount(int newUnreadCount, bool psUpdate) { } void History::setMute(bool newMute) { - if (mute != newMute) { - mute = newMute; - if (inChatList() && unreadCount) { - App::histories().unreadMuteChanged(unreadCount, newMute); - if (App::wnd()) App::wnd()->updateCounter(); + if (_mute != newMute) { + _mute = newMute; + if (inChatList(Dialogs::Mode::All)) { + if (_unreadCount) { + App::histories().unreadMuteChanged(_unreadCount, newMute); + if (App::wnd()) App::wnd()->updateCounter(); + } + Notify::historyMuteUpdated(this); } updateChatListEntry(); } @@ -1881,12 +1884,12 @@ void History::getNextScrollTopItem(HistoryBlock *block, int32 i) { } void History::addUnreadBar() { - if (unreadBar || !showFrom || showFrom->detached() || !unreadCount) return; + if (unreadBar || !showFrom || showFrom->detached() || !unreadCount()) return; - int32 count = unreadCount; + int32 count = unreadCount(); if (peer->migrateTo()) { if (History *h = App::historyLoaded(peer->migrateTo()->id)) { - count += h->unreadCount; + count += h->unreadCount(); } } showFrom->setUnreadBarCount(count); @@ -2014,12 +2017,12 @@ bool History::isReadyFor(MsgId msgId, MsgId &fixInScrollMsgId, int32 &fixInScrol if (msgId == ShowAtUnreadMsgId) { if (peer->migrateFrom()) { // old group history if (History *h = App::historyLoaded(peer->migrateFrom()->id)) { - if (h->unreadCount) { + if (h->unreadCount()) { return h->isReadyFor(msgId, fixInScrollMsgId, fixInScrollMsgTop); } } } - if (unreadCount) { + if (unreadCount()) { if (!isEmpty()) { return (loadedAtTop() || minMsgId() <= inboxReadBefore) && (loadedAtBottom() || maxMsgId() >= inboxReadBefore); } @@ -2045,7 +2048,7 @@ void History::getReadyFor(MsgId msgId, MsgId &fixInScrollMsgId, int32 &fixInScro } if (msgId == ShowAtUnreadMsgId && peer->migrateFrom()) { if (History *h = App::historyLoaded(peer->migrateFrom()->id)) { - if (h->unreadCount) { + if (h->unreadCount()) { clear(true); h->getReadyFor(msgId, fixInScrollMsgId, fixInScrollMsgTop); return; @@ -2084,12 +2087,12 @@ void History::setLastMessage(HistoryItem *msg) { } void History::setChatsListDate(const QDateTime &date) { - bool updateDialog = (App::main() && (!peer->isChannel() || peer->asChannel()->amIn() || !_chatListLinks.isEmpty())); - if (peer->migrateTo() && _chatListLinks.isEmpty()) { + bool updateDialog = (App::main() && (!peer->isChannel() || peer->asChannel()->amIn() || inChatList(Dialogs::Mode::All))); + if (peer->migrateTo() && !inChatList(Dialogs::Mode::All)) { updateDialog = false; } if (!lastMsgDate.isNull() && lastMsgDate >= date) { - if (!updateDialog || !_chatListLinks.isEmpty()) { + if (!updateDialog || !inChatList(Dialogs::Mode::All)) { return; } } @@ -2225,61 +2228,64 @@ void History::clearOnDestroy() { clearBlocks(false); } -QPair<int32, int32> History::adjustByPosInChatsList(Dialogs::IndexedList *indexed) { +QPair<int32, int32> History::adjustByPosInChatList(Dialogs::Mode list, Dialogs::IndexedList *indexed) { t_assert(indexed != nullptr); - Dialogs::Row *lnk = mainChatListLink(); + Dialogs::Row *lnk = mainChatListLink(list); int32 movedFrom = lnk->pos() * st::dlgHeight; - indexed->adjustByPos(_chatListLinks); + indexed->adjustByPos(chatListLinks(list)); int32 movedTo = lnk->pos() * st::dlgHeight; return qMakePair(movedFrom, movedTo); } -int History::posInChatList() const { - return mainChatListLink()->pos(); +int History::posInChatList(Dialogs::Mode list) const { + return mainChatListLink(list)->pos(); } -Dialogs::Row *History::addToChatList(Dialogs::IndexedList *indexed) { +Dialogs::Row *History::addToChatList(Dialogs::Mode list, Dialogs::IndexedList *indexed) { t_assert(indexed != nullptr); - if (!inChatList()) { - _chatListLinks = indexed->addToEnd(this); - if (unreadCount) { - App::histories().unreadIncrement(unreadCount, mute); + if (!inChatList(list)) { + chatListLinks(list) = indexed->addToEnd(this); + if (list == Dialogs::Mode::All && unreadCount()) { + App::histories().unreadIncrement(unreadCount(), mute()); if (App::wnd()) App::wnd()->updateCounter(); } } - return mainChatListLink(); + return mainChatListLink(list); } -void History::removeFromChatList(Dialogs::IndexedList *indexed) { +void History::removeFromChatList(Dialogs::Mode list, Dialogs::IndexedList *indexed) { t_assert(indexed != nullptr); - if (inChatList()) { + if (inChatList(list)) { indexed->del(peer); - _chatListLinks.clear(); - if (unreadCount) { - App::histories().unreadIncrement(-unreadCount, mute); + chatListLinks(list).clear(); + if (list == Dialogs::Mode::All && unreadCount()) { + App::histories().unreadIncrement(-unreadCount(), mute()); if (App::wnd()) App::wnd()->updateCounter(); } } } -void History::removeChatListEntryByLetter(QChar letter) { +void History::removeChatListEntryByLetter(Dialogs::Mode list, QChar letter) { t_assert(letter != 0); - if (inChatList()) { - _chatListLinks.remove(letter); + if (inChatList(list)) { + chatListLinks(list).remove(letter); } } -void History::addChatListEntryByLetter(QChar letter, Dialogs::Row *row) { +void History::addChatListEntryByLetter(Dialogs::Mode list, QChar letter, Dialogs::Row *row) { t_assert(letter != 0); - if (inChatList()) { - _chatListLinks.insert(letter, row); + if (inChatList(list)) { + chatListLinks(list).insert(letter, row); } } void History::updateChatListEntry() const { if (MainWidget *m = App::main()) { - if (inChatList()) { - m->dlgUpdated(mainChatListLink()); + if (inChatList(Dialogs::Mode::All)) { + m->dlgUpdated(Dialogs::Mode::All, mainChatListLink(Dialogs::Mode::All)); + if (inChatList(Dialogs::Mode::Important)) { + m->dlgUpdated(Dialogs::Mode::Important, mainChatListLink(Dialogs::Mode::Important)); + } } } } @@ -2986,8 +2992,8 @@ void HistoryItem::destroy() { history()->clearLastKeyboard(); if (App::main()) App::main()->updateBotKeyboard(history()); } - if ((!out() || isPost()) && unread() && history()->unreadCount > 0) { - history()->setUnreadCount(history()->unreadCount - 1); + if ((!out() || isPost()) && unread() && history()->unreadCount() > 0) { + history()->setUnreadCount(history()->unreadCount() - 1); } Global::RefPendingRepaintItems().remove(this); delete this; diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 607d8292b..095fc2c96 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -65,6 +65,9 @@ public: int32 unreadBadge() const { return _unreadFull - (cIncludeMuted() ? 0 : _unreadMuted); } + int32 unreadMutedCount() const { + return _unreadMuted; + } bool unreadOnlyMuted() const { return cIncludeMuted() ? (_unreadMuted >= _unreadFull) : false; } @@ -249,7 +252,13 @@ public: HistoryItem *lastImportantMessage() const; + int unreadCount() const { + return _unreadCount; + } void setUnreadCount(int newUnreadCount, bool psUpdate = true); + bool mute() const { + return _mute; + } void setMute(bool newMute); void getNextShowFrom(HistoryBlock *block, int i); void addUnreadBar(); @@ -266,18 +275,18 @@ public: void fixLastMessage(bool wasAtBottom); void setChatsListDate(const QDateTime &date); - QPair<int32, int32> adjustByPosInChatsList(Dialogs::IndexedList *indexed); uint64 sortKeyInChatList() const { return _sortKeyInChatList; } - bool inChatList() const { - return !_chatListLinks.isEmpty(); + QPair<int32, int32> adjustByPosInChatList(Dialogs::Mode list, Dialogs::IndexedList *indexed); + bool inChatList(Dialogs::Mode list) const { + return !chatListLinks(list).isEmpty(); } - int posInChatList() const; - Dialogs::Row *addToChatList(Dialogs::IndexedList *indexed); - void removeFromChatList(Dialogs::IndexedList *indexed); - void removeChatListEntryByLetter(QChar letter); - void addChatListEntryByLetter(QChar letter, Dialogs::Row *row); + int posInChatList(Dialogs::Mode list) const; + Dialogs::Row *addToChatList(Dialogs::Mode list, Dialogs::IndexedList *indexed); + void removeFromChatList(Dialogs::Mode list, Dialogs::IndexedList *indexed); + void removeChatListEntryByLetter(Dialogs::Mode list, QChar letter); + void addChatListEntryByLetter(Dialogs::Mode list, QChar letter, Dialogs::Row *row); void updateChatListEntry() const; MsgId minMsgId() const; @@ -334,7 +343,6 @@ public: int width = 0; int height = 0; int32 msgCount = 0; - int32 unreadCount = 0; MsgId inboxReadBefore = 1; MsgId outboxReadBefore = 1; HistoryItem *showFrom = nullptr; @@ -412,8 +420,6 @@ protected: public: - bool mute; - bool lastKeyboardInited = false; bool lastKeyboardUsed = false; MsgId lastKeyboardId = 0; @@ -536,11 +542,19 @@ private: return ~QFlags<Flags::enum_type>(f); } Flags _flags; + bool _mute; + int32 _unreadCount = 0; - Dialogs::RowsByLetter _chatListLinks; - Dialogs::Row *mainChatListLink() const { - auto it = _chatListLinks.constFind(0); - t_assert(it != _chatListLinks.cend()); + Dialogs::RowsByLetter _chatListLinks[2]; + Dialogs::RowsByLetter &chatListLinks(Dialogs::Mode list) { + return _chatListLinks[static_cast<int>(list)]; + } + const Dialogs::RowsByLetter &chatListLinks(Dialogs::Mode list) const { + return _chatListLinks[static_cast<int>(list)]; + } + Dialogs::Row *mainChatListLink(Dialogs::Mode list) const { + auto it = chatListLinks(list).constFind(0); + t_assert(it != chatListLinks(list).cend()); return it.value(); } uint64 _sortKeyInChatList = 0; // like ((unixtime) << 32) | (incremented counter) diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 0a7da493a..29c01c8d8 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -3270,7 +3270,7 @@ void HistoryWidget::notify_migrateUpdated(PeerData *peer) { showHistory(peer->migrateTo()->id, (_showAtMsgId > 0) ? (-_showAtMsgId) : _showAtMsgId, true); } else if ((_migrated ? _migrated->peer : 0) != peer->migrateFrom()) { History *migrated = peer->migrateFrom() ? App::history(peer->migrateFrom()->id) : 0; - if (_migrated || (migrated && migrated->unreadCount > 0)) { + if (_migrated || (migrated && migrated->unreadCount() > 0)) { showHistory(peer->id, peer->migrateFrom() ? _showAtMsgId : ((_showAtMsgId < 0 && -_showAtMsgId < ServerMaxMsgId) ? ShowAtUnreadMsgId : _showAtMsgId), true); } else { _migrated = migrated; @@ -3831,7 +3831,7 @@ void HistoryWidget::updateFieldSubmitSettings() { void HistoryWidget::updateNotifySettings() { if (!_peer || !_peer->isChannel()) return; - _muteUnmute.setText(lang(_history->mute ? lng_channel_unmute : lng_channel_mute)); + _muteUnmute.setText(lang(_history->mute() ? lng_channel_unmute : lng_channel_mute)); if (_peer->notify != UnknownNotifySettings) { _silent.setChecked(_peer->notify != EmptyNotifySettings && (_peer->notify->flags & MTPDpeerNotifySettings::Flag::f_silent)); if (_silent.isHidden() && hasSilentToggle()) { @@ -4211,7 +4211,7 @@ void HistoryWidget::newUnreadMsg(History *history, HistoryItem *item) { } } else { App::wnd()->notifySchedule(history, item); - history->setUnreadCount(history->unreadCount + 1); + history->setUnreadCount(history->unreadCount() + 1); } } else { if (_history == history) { @@ -4220,7 +4220,7 @@ void HistoryWidget::newUnreadMsg(History *history, HistoryItem *item) { } } App::wnd()->notifySchedule(history, item); - history->setUnreadCount(history->unreadCount + 1); + history->setUnreadCount(history->unreadCount() + 1); } } @@ -4339,7 +4339,7 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages } _firstLoadRequest = 0; if (_history->loadedAtTop()) { - if (_history->unreadCount > count) { + if (_history->unreadCount() > count) { _history->setUnreadCount(count); } if (_history->isEmpty() && count > 0) { @@ -4373,7 +4373,7 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages } _firstLoadRequest = 0; if (_history->loadedAtTop()) { - if (_history->unreadCount > count) { + if (_history->unreadCount() > count) { _history->setUnreadCount(count); } if (_history->isEmpty() && count > 0) { @@ -4429,12 +4429,12 @@ void HistoryWidget::firstLoadMessages() { PeerData *from = _peer; int32 offset_id = 0, offset = 0, loadCount = MessagesPerPage; if (_showAtMsgId == ShowAtUnreadMsgId) { - if (_migrated && _migrated->unreadCount) { + if (_migrated && _migrated->unreadCount()) { _history->getReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop); from = _migrated->peer; offset = -loadCount / 2; offset_id = _migrated->inboxReadBefore; - } else if (_history->unreadCount) { + } else if (_history->unreadCount()) { _history->getReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop); offset = -loadCount / 2; offset_id = _history->inboxReadBefore; @@ -4552,11 +4552,11 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) { PeerData *from = _peer; int32 offset_id = 0, offset = 0, loadCount = MessagesPerPage; if (_delayedShowAtMsgId == ShowAtUnreadMsgId) { - if (_migrated && _migrated->unreadCount) { + if (_migrated && _migrated->unreadCount()) { from = _migrated->peer; offset = -loadCount / 2; offset_id = _migrated->inboxReadBefore; - } else if (_history->unreadCount) { + } else if (_history->unreadCount()) { offset = -loadCount / 2; offset_id = _history->inboxReadBefore; } else { @@ -4872,7 +4872,7 @@ bool HistoryWidget::joinFail(const RPCError &error, mtpRequestId req) { } void HistoryWidget::onMuteUnmute() { - App::main()->updateNotifySetting(_peer, _history->mute ? NotifySettingSetNotify : NotifySettingSetMuted); + App::main()->updateNotifySetting(_peer, _history->mute() ? NotifySettingSetNotify : NotifySettingSetMuted); } void HistoryWidget::onBroadcastSilentChange() { @@ -6720,10 +6720,10 @@ void HistoryWidget::addMessagesToBack(PeerData *peer, const QVector<MTPMessage> } void HistoryWidget::countHistoryShowFrom() { - if (_migrated && _showAtMsgId == ShowAtUnreadMsgId && _migrated->unreadCount) { + if (_migrated && _showAtMsgId == ShowAtUnreadMsgId && _migrated->unreadCount()) { _migrated->updateShowFrom(); } - if ((_migrated && _migrated->showFrom) || _showAtMsgId != ShowAtUnreadMsgId || !_history->unreadCount) { + if ((_migrated && _migrated->showFrom) || _showAtMsgId != ShowAtUnreadMsgId || !_history->unreadCount()) { _history->showFrom = 0; return; } diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_result.h b/Telegram/SourceFiles/inline_bots/inline_bot_result.h index 54163ca34..567339c1c 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_result.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_result.h @@ -90,6 +90,7 @@ private: Gif, Article, Contact, + Geo, Venue, }; diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 61b831b94..386f307c4 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -552,65 +552,66 @@ namespace { }; enum { - dbiKey = 0x00, - dbiUser = 0x01, - dbiDcOptionOld = 0x02, - dbiChatSizeMax = 0x03, - dbiMutePeer = 0x04, - dbiSendKey = 0x05, - dbiAutoStart = 0x06, - dbiStartMinimized = 0x07, - dbiSoundNotify = 0x08, - dbiWorkMode = 0x09, - dbiSeenTrayTooltip = 0x0a, - dbiDesktopNotify = 0x0b, - dbiAutoUpdate = 0x0c, - dbiLastUpdateCheck = 0x0d, - dbiWindowPosition = 0x0e, - dbiConnectionType = 0x0f, + dbiKey = 0x00, + dbiUser = 0x01, + dbiDcOptionOld = 0x02, + dbiChatSizeMax = 0x03, + dbiMutePeer = 0x04, + dbiSendKey = 0x05, + dbiAutoStart = 0x06, + dbiStartMinimized = 0x07, + dbiSoundNotify = 0x08, + dbiWorkMode = 0x09, + dbiSeenTrayTooltip = 0x0a, + dbiDesktopNotify = 0x0b, + dbiAutoUpdate = 0x0c, + dbiLastUpdateCheck = 0x0d, + dbiWindowPosition = 0x0e, + dbiConnectionType = 0x0f, // 0x10 reserved - dbiDefaultAttach = 0x11, - dbiCatsAndDogs = 0x12, - dbiReplaceEmojis = 0x13, - dbiAskDownloadPath = 0x14, - dbiDownloadPathOld = 0x15, - dbiScale = 0x16, - dbiEmojiTabOld = 0x17, - dbiRecentEmojisOld = 0x18, - dbiLoggedPhoneNumber = 0x19, - dbiMutedPeers = 0x1a, + dbiDefaultAttach = 0x11, + dbiCatsAndDogs = 0x12, + dbiReplaceEmojis = 0x13, + dbiAskDownloadPath = 0x14, + dbiDownloadPathOld = 0x15, + dbiScale = 0x16, + dbiEmojiTabOld = 0x17, + dbiRecentEmojisOld = 0x18, + dbiLoggedPhoneNumber = 0x19, + dbiMutedPeers = 0x1a, // 0x1b reserved - dbiNotifyView = 0x1c, - dbiSendToMenu = 0x1d, - dbiCompressPastedImage = 0x1e, - dbiLang = 0x1f, - dbiLangFile = 0x20, - dbiTileBackground = 0x21, - dbiAutoLock = 0x22, - dbiDialogLastPath = 0x23, - dbiRecentEmojis = 0x24, - dbiEmojiVariants = 0x25, - dbiRecentStickers = 0x26, - dbiDcOption = 0x27, - dbiTryIPv6 = 0x28, - dbiSongVolume = 0x29, + dbiNotifyView = 0x1c, + dbiSendToMenu = 0x1d, + dbiCompressPastedImage = 0x1e, + dbiLang = 0x1f, + dbiLangFile = 0x20, + dbiTileBackground = 0x21, + dbiAutoLock = 0x22, + dbiDialogLastPath = 0x23, + dbiRecentEmojis = 0x24, + dbiEmojiVariants = 0x25, + dbiRecentStickers = 0x26, + dbiDcOption = 0x27, + dbiTryIPv6 = 0x28, + dbiSongVolume = 0x29, dbiWindowsNotifications = 0x30, - dbiIncludeMuted = 0x31, - dbiMegagroupSizeMax = 0x32, - dbiDownloadPath = 0x33, - dbiAutoDownload = 0x34, - dbiSavedGifsLimit = 0x35, - dbiShowingSavedGifs = 0x36, - dbiAutoPlay = 0x37, - dbiAdaptiveForWide = 0x38, + dbiIncludeMuted = 0x31, + dbiMegagroupSizeMax = 0x32, + dbiDownloadPath = 0x33, + dbiAutoDownload = 0x34, + dbiSavedGifsLimit = 0x35, + dbiShowingSavedGifs = 0x36, + dbiAutoPlay = 0x37, + dbiAdaptiveForWide = 0x38, dbiHiddenPinnedMessages = 0x39, + dbiDialogsMode = 0x40, - dbiEncryptedWithSalt = 333, - dbiEncrypted = 444, + dbiEncryptedWithSalt = 333, + dbiEncrypted = 444, // 500-600 reserved - dbiVersion = 666, + dbiVersion = 666, }; @@ -981,6 +982,22 @@ namespace { cSetAutoPlayGif(gif == 1); } break; + case dbiDialogsMode: { + qint32 enabled, modeInt; + stream >> enabled >> modeInt; + if (!_checkStreamStatus(stream)) return false; + + Global::SetDialogsModeEnabled(enabled == 1); + Dialogs::Mode mode = Dialogs::Mode::All; + if (enabled) { + mode = static_cast<Dialogs::Mode>(modeInt); + if (mode != Dialogs::Mode::All && mode != Dialogs::Mode::Important) { + mode = Dialogs::Mode::All; + } + } + Global::SetDialogsMode(mode); + } break; + case dbiIncludeMuted: { qint32 v; stream >> v; @@ -1578,6 +1595,7 @@ namespace { size += sizeof(quint32) + sizeof(qint32) + (cRecentStickersPreload().isEmpty() ? cGetRecentStickers().size() : cRecentStickersPreload().size()) * (sizeof(uint64) + sizeof(ushort)); size += sizeof(quint32) + Serialize::stringSize(cDialogLastPath()); size += sizeof(quint32) + 3 * sizeof(qint32); + size += sizeof(quint32) + 2 * sizeof(qint32); if (!Global::HiddenPinnedMessages().isEmpty()) { size += sizeof(quint32) + sizeof(qint32) + Global::HiddenPinnedMessages().size() * (sizeof(PeerId) + sizeof(MsgId)); } @@ -1601,6 +1619,7 @@ namespace { data.stream << quint32(dbiDialogLastPath) << cDialogLastPath(); data.stream << quint32(dbiSongVolume) << qint32(qRound(cSongVolume() * 1e6)); data.stream << quint32(dbiAutoDownload) << qint32(cAutoDownloadPhoto()) << qint32(cAutoDownloadAudio()) << qint32(cAutoDownloadGif()); + data.stream << quint32(dbiDialogsMode) << qint32(Global::DialogsModeEnabled() ? 1 : 0) << static_cast<qint32>(Global::DialogsMode()); data.stream << quint32(dbiAutoPlay) << qint32(cAutoPlayGif() ? 1 : 0); { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 7d79406ed..a6836b2ee 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -844,6 +844,10 @@ void MainWidget::notify_inlineItemLayoutChanged(const InlineBots::Layout::ItemBa history.notify_inlineItemLayoutChanged(layout); } +void MainWidget::notify_historyMuteUpdated(History *history) { + dialogs.notify_historyMuteUpdated(history); +} + void MainWidget::notify_handlePendingHistoryUpdate() { history.notify_handlePendingHistoryUpdate(); } @@ -1509,7 +1513,7 @@ void MainWidget::saveRecentHashtags(const QString &text) { } void MainWidget::readServerHistory(History *hist, bool force) { - if (!hist || (!force && !hist->unreadCount)) return; + if (!hist || (!force && !hist->unreadCount())) return; MsgId upTo = hist->inboxRead(0); if (hist->isChannel() && !hist->peer->asChannel()->amIn()) { @@ -2665,14 +2669,18 @@ QRect MainWidget::historyRect() const { return r; } -void MainWidget::dlgUpdated(Dialogs::Row *row) { - if (row) { - dialogs.dlgUpdated(row); - } else if (_peerInStack) { +void MainWidget::dlgUpdated() { + if (_peerInStack) { dialogs.dlgUpdated(App::history(_peerInStack->id), _msgIdInStack); } } +void MainWidget::dlgUpdated(Dialogs::Mode list, Dialogs::Row *row) { + if (row) { + dialogs.dlgUpdated(list, row); + } +} + void MainWidget::dlgUpdated(History *row, MsgId msgId) { if (!row) return; if (msgId < 0 && -msgId < ServerMaxMsgId && row->peer->migrateFrom()) { @@ -3113,7 +3121,7 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha h->setLastMessage(item); } int32 unreadCount = h->isMegagroup() ? d.vunread_count.v : d.vunread_important_count.v; - if (unreadCount >= h->unreadCount) { + if (unreadCount >= h->unreadCount()) { h->setUnreadCount(unreadCount, false); h->inboxReadBefore = d.vread_inbox_max_id.v + 1; } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index dc787f08a..945225f6b 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -260,7 +260,8 @@ public: void createDialog(History *history); void removeDialog(History *history); - void dlgUpdated(Dialogs::Row *row = nullptr); + void dlgUpdated(); + void dlgUpdated(Dialogs::Mode list, Dialogs::Row *row); void dlgUpdated(History *row, MsgId msgId); void windowShown(); @@ -467,6 +468,7 @@ public: void notify_clipStopperHidden(ClipStopperType type); void notify_historyItemLayoutChanged(const HistoryItem *item); void notify_inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout); + void notify_historyMuteUpdated(History *history); void notify_handlePendingHistoryUpdate(); void cmd_search(); diff --git a/Telegram/SourceFiles/settingswidget.cpp b/Telegram/SourceFiles/settingswidget.cpp index e53d898ee..cba8bc9ed 100644 --- a/Telegram/SourceFiles/settingswidget.cpp +++ b/Telegram/SourceFiles/settingswidget.cpp @@ -823,14 +823,22 @@ void SettingsInner::keyPressEvent(QKeyEvent *e) { } else { Global::RefDebugLoggingFlags() |= DebugLogging::FileLoaderFlag; } - Ui::showLayer(new InformBox(DebugLogging::FileLoader() ? "Enabled file download logging" : "Disabled file download logging")); + Ui::showLayer(new InformBox(DebugLogging::FileLoader() ? qsl("Enabled file download logging") : qsl("Disabled file download logging"))); } else if (str == qstr("crashplease")) { t_assert(!"Crashed in Settings!"); + } else if (str == qstr("workmode")) { + QString text = Global::DialogsModeEnabled() ? qsl("Disable work mode?") : qsl("Enable work mode?"); + auto box = std_::make_unique<ConfirmBox>(text); + connect(box.get(), SIGNAL(confirmed()), App::app(), SLOT(onSwitchWorkMode())); + Ui::showLayer(box.release()); + from = size; + break; } else if ( qsl("debugmode").startsWith(str) || qsl("testmode").startsWith(str) || qsl("loadlang").startsWith(str) || qsl("debugfiles").startsWith(str) || + qsl("workmode").startsWith(str) || qsl("crashplease").startsWith(str)) { break; } diff --git a/Telegram/ui/buttons/peer_avatar_button.cpp b/Telegram/ui/buttons/peer_avatar_button.cpp new file mode 100644 index 000000000..7dbadc50c --- /dev/null +++ b/Telegram/ui/buttons/peer_avatar_button.cpp @@ -0,0 +1,35 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "ui/buttons/peer_avatar_button.h" + +PeerAvatarButton::PeerAvatarButton(QWidget *parent, PeerData *peer, const style::PeerAvatarButton &st) : Button(parent) +, _peer(peer) +, _st(st) { + resize(_st.size, _st.size); +} + +void PeerAvatarButton::paintEvent(QPaintEvent *e) { + if (_peer) { + Painter p(this); + _peer->paintUserpic(p, _st.photoSize, (_st.size - _st.photoSize) / 2, (_st.size - _st.photoSize) / 2); + } +} diff --git a/Telegram/ui/buttons/peer_avatar_button.h b/Telegram/ui/buttons/peer_avatar_button.h new file mode 100644 index 000000000..d0861fef9 --- /dev/null +++ b/Telegram/ui/buttons/peer_avatar_button.h @@ -0,0 +1,40 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "ui/button.h" +#include "ui/style.h" +#include "structs.h" + +class PeerAvatarButton : public Button { +public: + PeerAvatarButton(QWidget *parent, PeerData *peer, const style::PeerAvatarButton &st); + void setPeer(PeerData *peer) { + _peer = peer; + update(); + } + void paintEvent(QPaintEvent *e); + +private: + PeerData *_peer; + const style::PeerAvatarButton &_st; + +};