Encapsulated unreadCount and mute fields in History.

Support for hiding all muted chats from the list.
This commit is contained in:
John Preston 2016-04-11 14:59:01 +04:00
parent 03bbb2269d
commit e0d6a68554
26 changed files with 1323 additions and 962 deletions

View File

@ -886,6 +886,8 @@ dlgPaddingVer: 8px;
dlgHeight: 62px;
dlgPhotoPadding: 12px;
dlgImportantHeight: 37px;
noContactsHeight: 100px;
noContactsFont: font(fsize);
noContactsColor: #777;

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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();

View File

@ -195,6 +195,7 @@ public slots:
void photoUpdated(const FullMsgId &msgId, bool silent, const MTPInputFile &file);
void onSwitchDebugMode();
void onSwitchWorkMode();
void onSwitchTestMode();
void killDownloadSessions();

View File

@ -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);

View File

@ -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();

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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*>;

View File

@ -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**>;

View File

@ -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:

View File

@ -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 &region, 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 &region, 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;
}

View File

@ -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:

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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;
}

View File

@ -90,6 +90,7 @@ private:
Gif,
Article,
Contact,
Geo,
Venue,
};

View File

@ -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);
{

View File

@ -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;
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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;
};