mirror of https://github.com/procxx/kepka.git
Refactored dialogs structs.
Moved DialogRow, FakeDialogRow, DialogsList and DialogsIndexed from history module to dialogs/ folder, for all struct -> class.
This commit is contained in:
parent
8f00650f0e
commit
7bba52fb7e
|
@ -19,19 +19,18 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "lang.h"
|
#include "boxes/contactsbox.h"
|
||||||
|
|
||||||
#include "addcontactbox.h"
|
#include "dialogs/dialogs_indexed_list.h"
|
||||||
#include "contactsbox.h"
|
#include "lang.h"
|
||||||
|
#include "boxes/addcontactbox.h"
|
||||||
|
#include "boxes/contactsbox.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
|
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
|
|
||||||
#include "ui/filedialog.h"
|
#include "ui/filedialog.h"
|
||||||
#include "photocropbox.h"
|
#include "boxes/photocropbox.h"
|
||||||
|
#include "boxes/confirmbox.h"
|
||||||
#include "confirmbox.h"
|
|
||||||
|
|
||||||
QString cantInviteError() {
|
QString cantInviteError() {
|
||||||
return lng_cant_invite_not_contact(lt_more_info, textcmdLink(qsl("https://telegram.me/spambot"), lang(lng_cant_more_info)));
|
return lng_cant_invite_not_contact(lt_more_info, textcmdLink(qsl("https://telegram.me/spambot"), lang(lng_cant_more_info)));
|
||||||
|
@ -40,53 +39,22 @@ QString cantInviteError() {
|
||||||
ContactsInner::ContactsInner(CreatingGroupType creating) : TWidget()
|
ContactsInner::ContactsInner(CreatingGroupType creating) : TWidget()
|
||||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||||
, _newItemHeight(creating == CreatingGroupNone ? st::contactsNewItemHeight : 0)
|
, _newItemHeight(creating == CreatingGroupNone ? st::contactsNewItemHeight : 0)
|
||||||
, _newItemSel(false)
|
|
||||||
, _chat(0)
|
|
||||||
, _channel(0)
|
|
||||||
, _membersFilter(MembersFilterRecent)
|
|
||||||
, _bot(0)
|
|
||||||
, _creating(creating)
|
, _creating(creating)
|
||||||
, _allAdmins(this, lang(lng_chat_all_members_admins), false, st::contactsAdminCheckbox)
|
, _allAdmins(this, lang(lng_chat_all_members_admins), false, st::contactsAdminCheckbox)
|
||||||
, _addToPeer(0)
|
, _contacts(App::main()->contactsList())
|
||||||
, _addAdmin(0)
|
, _addContactLnk(this, lang(lng_add_contact_button)) {
|
||||||
, _addAdminRequestId(0)
|
|
||||||
, _addAdminBox(0)
|
|
||||||
, _contacts(&App::main()->contactsList())
|
|
||||||
, _sel(0)
|
|
||||||
, _filteredSel(-1)
|
|
||||||
, _mouseSel(false)
|
|
||||||
, _selCount(0)
|
|
||||||
, _searching(false)
|
|
||||||
, _byUsernameSel(-1)
|
|
||||||
, _addContactLnk(this, lang(lng_add_contact_button))
|
|
||||||
, _saving(false) {
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
ContactsInner::ContactsInner(ChannelData *channel, MembersFilter membersFilter, const MembersAlreadyIn &already) : TWidget()
|
ContactsInner::ContactsInner(ChannelData *channel, MembersFilter membersFilter, const MembersAlreadyIn &already) : TWidget()
|
||||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||||
, _newItemHeight(0)
|
|
||||||
, _newItemSel(false)
|
|
||||||
, _chat(0)
|
|
||||||
, _channel(channel)
|
, _channel(channel)
|
||||||
, _membersFilter(membersFilter)
|
, _membersFilter(membersFilter)
|
||||||
, _bot(0)
|
|
||||||
, _creating(CreatingGroupChannel)
|
, _creating(CreatingGroupChannel)
|
||||||
, _already(already)
|
, _already(already)
|
||||||
, _allAdmins(this, lang(lng_chat_all_members_admins), false, st::contactsAdminCheckbox)
|
, _allAdmins(this, lang(lng_chat_all_members_admins), false, st::contactsAdminCheckbox)
|
||||||
, _addToPeer(0)
|
, _contacts(App::main()->contactsList())
|
||||||
, _addAdmin(0)
|
, _addContactLnk(this, lang(lng_add_contact_button)) {
|
||||||
, _addAdminRequestId(0)
|
|
||||||
, _addAdminBox(0)
|
|
||||||
, _contacts(&App::main()->contactsList())
|
|
||||||
, _sel(0)
|
|
||||||
, _filteredSel(-1)
|
|
||||||
, _mouseSel(false)
|
|
||||||
, _selCount(0)
|
|
||||||
, _searching(false)
|
|
||||||
, _byUsernameSel(-1)
|
|
||||||
, _addContactLnk(this, lang(lng_add_contact_button))
|
|
||||||
, _saving(false) {
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,34 +66,19 @@ namespace {
|
||||||
|
|
||||||
ContactsInner::ContactsInner(ChatData *chat, MembersFilter membersFilter) : TWidget()
|
ContactsInner::ContactsInner(ChatData *chat, MembersFilter membersFilter) : TWidget()
|
||||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||||
, _newItemHeight(0)
|
|
||||||
, _newItemSel(false)
|
|
||||||
, _chat(chat)
|
, _chat(chat)
|
||||||
, _channel(0)
|
|
||||||
, _membersFilter(membersFilter)
|
, _membersFilter(membersFilter)
|
||||||
, _bot(0)
|
|
||||||
, _creating(CreatingGroupNone)
|
|
||||||
, _allAdmins(this, lang(lng_chat_all_members_admins), !_chat->adminsEnabled(), st::contactsAdminCheckbox)
|
, _allAdmins(this, lang(lng_chat_all_members_admins), !_chat->adminsEnabled(), st::contactsAdminCheckbox)
|
||||||
, _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.right() - st::contactsCheckPosition.x() * 2 - st::contactsCheckIcon.pxWidth())
|
, _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.right() - st::contactsCheckPosition.x() * 2 - st::contactsCheckIcon.pxWidth())
|
||||||
, _aboutAllAdmins(st::boxTextFont, lang(lng_chat_about_all_admins), _defaultOptions, _aboutWidth)
|
, _aboutAllAdmins(st::boxTextFont, lang(lng_chat_about_all_admins), _defaultOptions, _aboutWidth)
|
||||||
, _aboutAdmins(st::boxTextFont, lang(lng_chat_about_admins), _defaultOptions, _aboutWidth)
|
, _aboutAdmins(st::boxTextFont, lang(lng_chat_about_admins), _defaultOptions, _aboutWidth)
|
||||||
, _addToPeer(0)
|
, _customList((membersFilter == MembersFilterRecent) ? UniquePointer<Dialogs::IndexedList>() : MakeUnique<Dialogs::IndexedList>(Dialogs::SortMode::Add))
|
||||||
, _addAdmin(0)
|
, _contacts((membersFilter == MembersFilterRecent) ? App::main()->contactsList() : _customList.data())
|
||||||
, _addAdminRequestId(0)
|
, _addContactLnk(this, lang(lng_add_contact_button)) {
|
||||||
, _addAdminBox(0)
|
|
||||||
, _contacts((membersFilter == MembersFilterRecent) ? (&App::main()->contactsList()) : (new DialogsIndexed(DialogsSortByAdd)))
|
|
||||||
, _sel(0)
|
|
||||||
, _filteredSel(-1)
|
|
||||||
, _mouseSel(false)
|
|
||||||
, _selCount(0)
|
|
||||||
, _searching(false)
|
|
||||||
, _byUsernameSel(-1)
|
|
||||||
, _addContactLnk(this, lang(lng_add_contact_button))
|
|
||||||
, _saving(false) {
|
|
||||||
initList();
|
initList();
|
||||||
if (membersFilter == MembersFilterAdmins) {
|
if (membersFilter == MembersFilterAdmins) {
|
||||||
_newItemHeight = st::contactsNewItemHeight + qMax(_aboutAllAdmins.countHeight(_aboutWidth), _aboutAdmins.countHeight(_aboutWidth)) + st::contactsAboutHeight;
|
_newItemHeight = st::contactsNewItemHeight + qMax(_aboutAllAdmins.countHeight(_aboutWidth), _aboutAdmins.countHeight(_aboutWidth)) + st::contactsAboutHeight;
|
||||||
if (!_contacts->list.count) {
|
if (_contacts->isEmpty()) {
|
||||||
App::api()->requestFullPeer(_chat);
|
App::api()->requestFullPeer(_chat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,33 +87,18 @@ ContactsInner::ContactsInner(ChatData *chat, MembersFilter membersFilter) : TWid
|
||||||
|
|
||||||
ContactsInner::ContactsInner(UserData *bot) : TWidget()
|
ContactsInner::ContactsInner(UserData *bot) : TWidget()
|
||||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||||
, _newItemHeight(0)
|
|
||||||
, _newItemSel(false)
|
|
||||||
, _chat(0)
|
|
||||||
, _channel(0)
|
|
||||||
, _membersFilter(MembersFilterRecent)
|
|
||||||
, _bot(bot)
|
, _bot(bot)
|
||||||
, _creating(CreatingGroupNone)
|
|
||||||
, _allAdmins(this, lang(lng_chat_all_members_admins), false, st::contactsAdminCheckbox)
|
, _allAdmins(this, lang(lng_chat_all_members_admins), false, st::contactsAdminCheckbox)
|
||||||
, _addToPeer(0)
|
, _customList(MakeUnique<Dialogs::IndexedList>(Dialogs::SortMode::Add))
|
||||||
, _addAdmin(0)
|
, _contacts(_customList.data())
|
||||||
, _addAdminRequestId(0)
|
, _addContactLnk(this, lang(lng_add_contact_button)) {
|
||||||
, _addAdminBox(0)
|
auto v = App::main()->dialogsList();
|
||||||
, _contacts(new DialogsIndexed(DialogsSortByAdd))
|
for_const (auto row, *v) {
|
||||||
, _sel(0)
|
auto peer = row->history()->peer;
|
||||||
, _filteredSel(-1)
|
if (peer->isChat() && peer->asChat()->canEdit()) {
|
||||||
, _mouseSel(false)
|
_contacts->addToEnd(row->history());
|
||||||
, _selCount(0)
|
} else if (peer->isMegagroup() && (peer->asChannel()->amCreator() || peer->asChannel()->amEditor())) {
|
||||||
, _searching(false)
|
_contacts->addToEnd(row->history());
|
||||||
, _byUsernameSel(-1)
|
|
||||||
, _addContactLnk(this, lang(lng_add_contact_button))
|
|
||||||
, _saving(false) {
|
|
||||||
DialogsIndexed &v(App::main()->dialogsList());
|
|
||||||
for (DialogRow *r = v.list.begin; r != v.list.end; r = r->next) {
|
|
||||||
if (r->history->peer->isChat() && r->history->peer->asChat()->canEdit()) {
|
|
||||||
_contacts->addToEnd(r->history);
|
|
||||||
} else if (r->history->peer->isMegagroup() && (r->history->peer->asChannel()->amCreator() || r->history->peer->asChannel()->amEditor())) {
|
|
||||||
_contacts->addToEnd(r->history);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
init();
|
init();
|
||||||
|
@ -173,14 +111,14 @@ void ContactsInner::init() {
|
||||||
|
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
|
||||||
for (DialogRow *r = _contacts->list.begin; r != _contacts->list.end; r = r->next) {
|
for_const (auto row, _contacts->all()) {
|
||||||
r->attached = 0;
|
row->attached = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
_filter = qsl("a");
|
_filter = qsl("a");
|
||||||
updateFilter();
|
updateFilter();
|
||||||
|
|
||||||
connect(App::main(), SIGNAL(dialogRowReplaced(DialogRow*,DialogRow*)), this, SLOT(onDialogRowReplaced(DialogRow*,DialogRow*)));
|
connect(App::main(), SIGNAL(dialogRowReplaced(Dialogs::Row*,Dialogs::Row*)), this, SLOT(onDialogRowReplaced(Dialogs::Row*,Dialogs::Row*)));
|
||||||
connect(App::main(), SIGNAL(peerUpdated(PeerData*)), this, SLOT(peerUpdated(PeerData *)));
|
connect(App::main(), SIGNAL(peerUpdated(PeerData*)), this, SLOT(peerUpdated(PeerData *)));
|
||||||
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*)));
|
connect(App::main(), SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(peerUpdated(PeerData*)));
|
||||||
|
@ -305,7 +243,7 @@ void ContactsInner::saving(bool flag) {
|
||||||
void ContactsInner::peerUpdated(PeerData *peer) {
|
void ContactsInner::peerUpdated(PeerData *peer) {
|
||||||
if (_chat && (!peer || peer == _chat)) {
|
if (_chat && (!peer || peer == _chat)) {
|
||||||
bool inited = false;
|
bool inited = false;
|
||||||
if (_membersFilter == MembersFilterAdmins && !_contacts->list.count && !_chat->participants.isEmpty()) {
|
if (_membersFilter == MembersFilterAdmins && _contacts->isEmpty() && !_chat->participants.isEmpty()) {
|
||||||
initList();
|
initList();
|
||||||
inited = true;
|
inited = true;
|
||||||
}
|
}
|
||||||
|
@ -316,8 +254,8 @@ void ContactsInner::peerUpdated(PeerData *peer) {
|
||||||
delete i.value();
|
delete i.value();
|
||||||
}
|
}
|
||||||
_contactsData.clear();
|
_contactsData.clear();
|
||||||
for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) {
|
for_const (auto row, _contacts->all()) {
|
||||||
row->attached = 0;
|
row->attached = nullptr;
|
||||||
}
|
}
|
||||||
if (!_filter.isEmpty()) {
|
if (!_filter.isEmpty()) {
|
||||||
for (int32 j = 0, s = _filtered.size(); j < s; ++j) {
|
for (int32 j = 0, s = _filtered.size(); j < s; ++j) {
|
||||||
|
@ -333,10 +271,10 @@ void ContactsInner::peerUpdated(PeerData *peer) {
|
||||||
} else {
|
} else {
|
||||||
ContactsData::iterator i = _contactsData.find(peer);
|
ContactsData::iterator i = _contactsData.find(peer);
|
||||||
if (i != _contactsData.cend()) {
|
if (i != _contactsData.cend()) {
|
||||||
for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) {
|
for_const (auto row, _contacts->all()) {
|
||||||
if (row->attached == i.value()) {
|
if (row->attached == i.value()) {
|
||||||
row->attached = 0;
|
row->attached = nullptr;
|
||||||
update(0, _newItemHeight + _rowHeight * row->pos, width(), _rowHeight);
|
update(0, _newItemHeight + _rowHeight * row->pos(), width(), _rowHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!_filter.isEmpty()) {
|
if (!_filter.isEmpty()) {
|
||||||
|
@ -361,14 +299,13 @@ void ContactsInner::loadProfilePhotos(int32 yFrom) {
|
||||||
if (yFrom < 0) yFrom = 0;
|
if (yFrom < 0) yFrom = 0;
|
||||||
|
|
||||||
if (_filter.isEmpty()) {
|
if (_filter.isEmpty()) {
|
||||||
if (_contacts->list.count) {
|
if (!_contacts->isEmpty()) {
|
||||||
_contacts->list.adjustCurrent(yFrom - _newItemHeight, _rowHeight);
|
auto i = _contacts->cfind(yFrom - _newItemHeight, _rowHeight);
|
||||||
for (
|
for (auto end = _contacts->cend(); i != end; ++i) {
|
||||||
DialogRow *preloadFrom = _contacts->list.current;
|
if ((_newItemHeight + (*i)->pos() * _rowHeight) >= yTo) {
|
||||||
preloadFrom != _contacts->list.end && (_newItemHeight + preloadFrom->pos * _rowHeight) < yTo;
|
break;
|
||||||
preloadFrom = preloadFrom->next
|
}
|
||||||
) {
|
(*i)->history()->peer->loadUserpic();
|
||||||
preloadFrom->history->peer->loadUserpic();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!_filtered.isEmpty()) {
|
} else if (!_filtered.isEmpty()) {
|
||||||
|
@ -379,16 +316,16 @@ void ContactsInner::loadProfilePhotos(int32 yFrom) {
|
||||||
if (to > _filtered.size()) to = _filtered.size();
|
if (to > _filtered.size()) to = _filtered.size();
|
||||||
|
|
||||||
for (; from < to; ++from) {
|
for (; from < to; ++from) {
|
||||||
_filtered[from]->history->peer->loadUserpic();
|
_filtered[from]->history()->peer->loadUserpic();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ContactsInner::ContactData *ContactsInner::contactData(DialogRow *row) {
|
ContactsInner::ContactData *ContactsInner::contactData(Dialogs::Row *row) {
|
||||||
ContactData *data = (ContactData*)row->attached;
|
ContactData *data = (ContactData*)row->attached;
|
||||||
if (!data) {
|
if (!data) {
|
||||||
PeerData *peer = row->history->peer;
|
PeerData *peer = row->history()->peer;
|
||||||
ContactsData::const_iterator i = _contactsData.constFind(peer);
|
ContactsData::const_iterator i = _contactsData.constFind(peer);
|
||||||
if (i == _contactsData.cend()) {
|
if (i == _contactsData.cend()) {
|
||||||
_contactsData.insert(peer, data = new ContactData());
|
_contactsData.insert(peer, data = new ContactData());
|
||||||
|
@ -513,7 +450,7 @@ void ContactsInner::paintEvent(QPaintEvent *e) {
|
||||||
|
|
||||||
int32 yFrom = r.y(), yTo = r.y() + r.height();
|
int32 yFrom = r.y(), yTo = r.y() + r.height();
|
||||||
if (_filter.isEmpty()) {
|
if (_filter.isEmpty()) {
|
||||||
if (_contacts->list.count || !_byUsername.isEmpty()) {
|
if (!_contacts->isEmpty() || !_byUsername.isEmpty()) {
|
||||||
if (_newItemHeight) {
|
if (_newItemHeight) {
|
||||||
if (_chat) {
|
if (_chat) {
|
||||||
p.fillRect(0, 0, width(), _newItemHeight - st::contactsPadding.bottom() - st::lineWidth, st::contactsAboutBg);
|
p.fillRect(0, 0, width(), _newItemHeight - st::contactsPadding.bottom() - st::lineWidth, st::contactsAboutBg);
|
||||||
|
@ -534,18 +471,18 @@ void ContactsInner::paintEvent(QPaintEvent *e) {
|
||||||
yTo -= _newItemHeight;
|
yTo -= _newItemHeight;
|
||||||
p.translate(0, _newItemHeight);
|
p.translate(0, _newItemHeight);
|
||||||
}
|
}
|
||||||
if (_contacts->list.count) {
|
if (!_contacts->isEmpty()) {
|
||||||
_contacts->list.adjustCurrent(yFrom, _rowHeight);
|
auto i = _contacts->cfind(yFrom, _rowHeight);
|
||||||
|
p.translate(0, (*i)->pos() * _rowHeight);
|
||||||
DialogRow *drawFrom = _contacts->list.current;
|
for (auto end = _contacts->cend(); i != end; ++i) {
|
||||||
p.translate(0, drawFrom->pos * _rowHeight);
|
if ((*i)->pos() * _rowHeight >= yTo) {
|
||||||
while (drawFrom != _contacts->list.end && drawFrom->pos * _rowHeight < yTo) {
|
break;
|
||||||
paintDialog(p, drawFrom->history->peer, contactData(drawFrom), (drawFrom == _sel));
|
}
|
||||||
|
paintDialog(p, (*i)->history()->peer, contactData(*i), (*i == _sel));
|
||||||
p.translate(0, _rowHeight);
|
p.translate(0, _rowHeight);
|
||||||
drawFrom = drawFrom->next;
|
|
||||||
}
|
}
|
||||||
yFrom -= _contacts->list.count * _rowHeight;
|
yFrom -= _contacts->size() * _rowHeight;
|
||||||
yTo -= _contacts->list.count * _rowHeight;
|
yTo -= _contacts->size() * _rowHeight;
|
||||||
}
|
}
|
||||||
if (!_byUsername.isEmpty()) {
|
if (!_byUsername.isEmpty()) {
|
||||||
p.fillRect(0, 0, width(), st::searchedBarHeight, st::searchedBarBG->b);
|
p.fillRect(0, 0, width(), st::searchedBarHeight, st::searchedBarBG->b);
|
||||||
|
@ -609,7 +546,7 @@ void ContactsInner::paintEvent(QPaintEvent *e) {
|
||||||
int32 to = ceilclamp(yTo, _rowHeight, 0, _filtered.size());
|
int32 to = ceilclamp(yTo, _rowHeight, 0, _filtered.size());
|
||||||
p.translate(0, from * _rowHeight);
|
p.translate(0, from * _rowHeight);
|
||||||
for (; from < to; ++from) {
|
for (; from < to; ++from) {
|
||||||
paintDialog(p, _filtered[from]->history->peer, contactData(_filtered[from]), (_filteredSel == from));
|
paintDialog(p, _filtered[from]->history()->peer, contactData(_filtered[from]), (_filteredSel == from));
|
||||||
p.translate(0, _rowHeight);
|
p.translate(0, _rowHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -644,10 +581,10 @@ void ContactsInner::updateSelectedRow() {
|
||||||
update(0, 0, width(), st::contactsNewItemHeight);
|
update(0, 0, width(), st::contactsNewItemHeight);
|
||||||
}
|
}
|
||||||
if (_sel) {
|
if (_sel) {
|
||||||
update(0, _newItemHeight + _sel->pos * _rowHeight, width(), _rowHeight);
|
update(0, _newItemHeight + _sel->pos() * _rowHeight, width(), _rowHeight);
|
||||||
}
|
}
|
||||||
if (_byUsernameSel >= 0) {
|
if (_byUsernameSel >= 0) {
|
||||||
update(0, _newItemHeight + _contacts->list.count * _rowHeight + st::searchedBarHeight + _byUsernameSel * _rowHeight, width(), _rowHeight);
|
update(0, _newItemHeight + _contacts->size() * _rowHeight + st::searchedBarHeight + _byUsernameSel * _rowHeight, width(), _rowHeight);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (_filteredSel >= 0) {
|
if (_filteredSel >= 0) {
|
||||||
|
@ -738,14 +675,14 @@ void ContactsInner::chooseParticipant() {
|
||||||
if (_byUsernameSel >= 0 && _byUsernameSel < _byUsername.size()) {
|
if (_byUsernameSel >= 0 && _byUsernameSel < _byUsername.size()) {
|
||||||
peer = _byUsername[_byUsernameSel];
|
peer = _byUsername[_byUsernameSel];
|
||||||
} else if (_sel) {
|
} else if (_sel) {
|
||||||
peer = _sel->history->peer;
|
peer = _sel->history()->peer;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (_byUsernameSel >= 0 && _byUsernameSel < _byUsernameFiltered.size()) {
|
if (_byUsernameSel >= 0 && _byUsernameSel < _byUsernameFiltered.size()) {
|
||||||
peer = _byUsernameFiltered[_byUsernameSel];
|
peer = _byUsernameFiltered[_byUsernameSel];
|
||||||
} else {
|
} else {
|
||||||
if (_filteredSel < 0 || _filteredSel >= _filtered.size()) return;
|
if (_filteredSel < 0 || _filteredSel >= _filtered.size()) return;
|
||||||
peer = _filtered[_filteredSel]->history->peer;
|
peer = _filtered[_filteredSel]->history()->peer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (peer) {
|
if (peer) {
|
||||||
|
@ -775,8 +712,8 @@ void ContactsInner::chooseParticipant() {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContactsInner::changeCheckState(DialogRow *row) {
|
void ContactsInner::changeCheckState(Dialogs::Row *row) {
|
||||||
changeCheckState(contactData(row), row->history->peer);
|
changeCheckState(contactData(row), row->history()->peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContactsInner::changeCheckState(ContactData *data, PeerData *peer) {
|
void ContactsInner::changeCheckState(ContactData *data, PeerData *peer) {
|
||||||
|
@ -822,8 +759,8 @@ void ContactsInner::updateSel() {
|
||||||
}
|
}
|
||||||
p.setY(p.y() - _newItemHeight);
|
p.setY(p.y() - _newItemHeight);
|
||||||
}
|
}
|
||||||
DialogRow *newSel = (in && !newItemSel && (p.y() >= 0) && (p.y() < _contacts->list.count * _rowHeight)) ? _contacts->list.rowAtY(p.y(), _rowHeight) : 0;
|
Dialogs::Row *newSel = (in && !newItemSel && (p.y() >= 0) && (p.y() < _contacts->size() * _rowHeight)) ? _contacts->rowAtY(p.y(), _rowHeight) : nullptr;
|
||||||
int32 byUsernameSel = (in && !newItemSel && p.y() >= _contacts->list.count * _rowHeight + st::searchedBarHeight) ? ((p.y() - _contacts->list.count * _rowHeight - st::searchedBarHeight) / _rowHeight) : -1;
|
int32 byUsernameSel = (in && !newItemSel && p.y() >= _contacts->size() * _rowHeight + st::searchedBarHeight) ? ((p.y() - _contacts->size() * _rowHeight - st::searchedBarHeight) / _rowHeight) : -1;
|
||||||
if (byUsernameSel >= _byUsername.size()) byUsernameSel = -1;
|
if (byUsernameSel >= _byUsername.size()) byUsernameSel = -1;
|
||||||
if (newSel != _sel || byUsernameSel != _byUsernameSel || newItemSel != _newItemSel) {
|
if (newSel != _sel || byUsernameSel != _byUsernameSel || newItemSel != _newItemSel) {
|
||||||
updateSelectedRow();
|
updateSelectedRow();
|
||||||
|
@ -883,23 +820,23 @@ void ContactsInner::updateFilter(QString filter) {
|
||||||
|
|
||||||
_filtered.clear();
|
_filtered.clear();
|
||||||
if (!f.isEmpty()) {
|
if (!f.isEmpty()) {
|
||||||
DialogsList *dialogsToFilter = 0;
|
const Dialogs::List *toFilter = nullptr;
|
||||||
if (_contacts->list.count) {
|
if (!_contacts->isEmpty()) {
|
||||||
for (fi = fb; fi != fe; ++fi) {
|
for (fi = fb; fi != fe; ++fi) {
|
||||||
DialogsIndexed::DialogsIndex::iterator i = _contacts->index.find(fi->at(0));
|
auto found = _contacts->filtered(fi->at(0));
|
||||||
if (i == _contacts->index.cend()) {
|
if (found->isEmpty()) {
|
||||||
dialogsToFilter = 0;
|
toFilter = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!dialogsToFilter || dialogsToFilter->count > i.value()->count) {
|
if (!toFilter || toFilter->size() > found->size()) {
|
||||||
dialogsToFilter = i.value();
|
toFilter = found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dialogsToFilter && dialogsToFilter->count) {
|
if (toFilter) {
|
||||||
_filtered.reserve(dialogsToFilter->count);
|
_filtered.reserve(toFilter->size());
|
||||||
for (DialogRow *i = dialogsToFilter->begin, *e = dialogsToFilter->end; i != e; i = i->next) {
|
for_const (auto row, *toFilter) {
|
||||||
const PeerData::Names &names(i->history->peer->names);
|
const PeerData::Names &names(row->history()->peer->names);
|
||||||
PeerData::Names::const_iterator nb = names.cbegin(), ne = names.cend(), ni;
|
PeerData::Names::const_iterator nb = names.cbegin(), ne = names.cend(), ni;
|
||||||
for (fi = fb; fi != fe; ++fi) {
|
for (fi = fb; fi != fe; ++fi) {
|
||||||
QString filterName(*fi);
|
QString filterName(*fi);
|
||||||
|
@ -913,8 +850,8 @@ void ContactsInner::updateFilter(QString filter) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fi == fe) {
|
if (fi == fe) {
|
||||||
i->attached = 0;
|
row->attached = nullptr;
|
||||||
_filtered.push_back(i);
|
_filtered.push_back(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -968,7 +905,7 @@ void ContactsInner::updateFilter(QString filter) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContactsInner::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) {
|
void ContactsInner::onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow) {
|
||||||
if (!_filter.isEmpty()) {
|
if (!_filter.isEmpty()) {
|
||||||
for (FilteredDialogs::iterator i = _filtered.begin(), e = _filtered.end(); i != e;) {
|
for (FilteredDialogs::iterator i = _filtered.begin(), e = _filtered.end(); i != e;) {
|
||||||
if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts!
|
if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts!
|
||||||
|
@ -991,8 +928,8 @@ void ContactsInner::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_mouseSel = false;
|
_mouseSel = false;
|
||||||
int32 cnt = (_filter.isEmpty() ? _contacts->list.count : _filtered.size());
|
int cnt = (_filter.isEmpty() ? _contacts->size() : _filtered.size());
|
||||||
int32 newh = cnt ? (cnt * _rowHeight) : st::noContactsHeight;
|
int newh = cnt ? (cnt * _rowHeight) : st::noContactsHeight;
|
||||||
resize(width(), newh);
|
resize(width(), newh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1050,9 +987,9 @@ void ContactsInner::refresh() {
|
||||||
} else {
|
} else {
|
||||||
if (!_allAdmins.isHidden()) _allAdmins.hide();
|
if (!_allAdmins.isHidden()) _allAdmins.hide();
|
||||||
}
|
}
|
||||||
if (_contacts->list.count || !_byUsername.isEmpty()) {
|
if (!_contacts->isEmpty() || !_byUsername.isEmpty()) {
|
||||||
if (!_addContactLnk.isHidden()) _addContactLnk.hide();
|
if (!_addContactLnk.isHidden()) _addContactLnk.hide();
|
||||||
resize(width(), _newItemHeight + (_contacts->list.count * _rowHeight) + (_byUsername.isEmpty() ? 0 : (st::searchedBarHeight + _byUsername.size() * _rowHeight)));
|
resize(width(), _newItemHeight + (_contacts->size() * _rowHeight) + (_byUsername.isEmpty() ? 0 : (st::searchedBarHeight + _byUsername.size() * _rowHeight)));
|
||||||
} else if (_chat && _membersFilter == MembersFilterAdmins) {
|
} else if (_chat && _membersFilter == MembersFilterAdmins) {
|
||||||
if (!_addContactLnk.isHidden()) _addContactLnk.hide();
|
if (!_addContactLnk.isHidden()) _addContactLnk.hide();
|
||||||
resize(width(), _newItemHeight + st::noContactsHeight);
|
resize(width(), _newItemHeight + st::noContactsHeight);
|
||||||
|
@ -1101,7 +1038,6 @@ ContactsInner::~ContactsInner() {
|
||||||
delete *i;
|
delete *i;
|
||||||
}
|
}
|
||||||
if (_bot || (_chat && _membersFilter == MembersFilterAdmins)) {
|
if (_bot || (_chat && _membersFilter == MembersFilterAdmins)) {
|
||||||
delete _contacts;
|
|
||||||
if (_bot && _bot->botInfo) _bot->botInfo->startGroupToken = QString();
|
if (_bot && _bot->botInfo) _bot->botInfo->startGroupToken = QString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1117,12 +1053,12 @@ void ContactsInner::selectSkip(int32 dir) {
|
||||||
if (_filter.isEmpty()) {
|
if (_filter.isEmpty()) {
|
||||||
int cur = 0;
|
int cur = 0;
|
||||||
if (_sel) {
|
if (_sel) {
|
||||||
for (DialogRow *i = _contacts->list.begin; i != _sel; i = i->next) {
|
for (auto i = _contacts->cbegin(); *i != _sel; ++i) {
|
||||||
++cur;
|
++cur;
|
||||||
}
|
}
|
||||||
if (_newItemHeight) ++cur;
|
if (_newItemHeight) ++cur;
|
||||||
} else if (_byUsernameSel >= 0) {
|
} else if (_byUsernameSel >= 0) {
|
||||||
cur = (_contacts->list.count + _byUsernameSel);
|
cur = (_contacts->size() + _byUsernameSel);
|
||||||
if (_newItemHeight) ++cur;
|
if (_newItemHeight) ++cur;
|
||||||
} else if (!_newItemSel) {
|
} else if (!_newItemSel) {
|
||||||
cur = -1;
|
cur = -1;
|
||||||
|
@ -1130,32 +1066,39 @@ void ContactsInner::selectSkip(int32 dir) {
|
||||||
cur += dir;
|
cur += dir;
|
||||||
if (cur <= 0) {
|
if (cur <= 0) {
|
||||||
_newItemSel = (_chat && _membersFilter == MembersFilterAdmins) ? false : (_newItemHeight ? true : false);
|
_newItemSel = (_chat && _membersFilter == MembersFilterAdmins) ? false : (_newItemHeight ? true : false);
|
||||||
_sel = (!_newItemHeight && _contacts->list.count) ? _contacts->list.begin : 0;
|
_sel = (!_newItemHeight && !_contacts->isEmpty()) ? *_contacts->cbegin() : nullptr;
|
||||||
_byUsernameSel = (!_newItemHeight && !_contacts->list.count && !_byUsername.isEmpty()) ? 0 : -1;
|
_byUsernameSel = (!_newItemHeight && _contacts->isEmpty() && !_byUsername.isEmpty()) ? 0 : -1;
|
||||||
} else if (cur >= _contacts->list.count + (_newItemHeight ? 1 : 0)) {
|
} else if (cur >= _contacts->size() + (_newItemHeight ? 1 : 0)) {
|
||||||
_newItemSel = false;
|
_newItemSel = false;
|
||||||
if (_byUsername.isEmpty()) {
|
if (_byUsername.isEmpty()) {
|
||||||
_sel = _contacts->list.count ? _contacts->list.end->prev : 0;
|
_sel = _contacts->isEmpty() ? nullptr : *(_contacts->cend() - 1);
|
||||||
_byUsernameSel = -1;
|
_byUsernameSel = -1;
|
||||||
} else {
|
} else {
|
||||||
_sel = 0;
|
_sel = nullptr;
|
||||||
_byUsernameSel = cur - _contacts->list.count;
|
_byUsernameSel = cur - _contacts->size();
|
||||||
if (_byUsernameSel >= _byUsername.size()) _byUsernameSel = _byUsername.size() - 1;
|
if (_byUsernameSel >= _byUsername.size()) _byUsernameSel = _byUsername.size() - 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_newItemSel = false;
|
_newItemSel = false;
|
||||||
if (_newItemHeight) --cur;
|
if (_newItemHeight) --cur;
|
||||||
for (_sel = _contacts->list.begin; cur; _sel = _sel->next) {
|
for (auto i = _contacts->cbegin(); ; ++i) {
|
||||||
--cur;
|
_sel = *i;
|
||||||
|
if (!cur) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
--cur;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_byUsernameSel = -1;
|
_byUsernameSel = -1;
|
||||||
}
|
}
|
||||||
if (dir > 0) {
|
if (dir > 0) {
|
||||||
while (_sel && _sel->next && contactData(_sel)->inchat) {
|
for (auto i = _contacts->cfind(_sel), end = _contacts->cend(); i != end && contactData(*i)->inchat; ++i) {
|
||||||
_sel = _sel->next;
|
_sel = *i;
|
||||||
}
|
}
|
||||||
if (!_sel || !_sel->next) {
|
if (contactData(_sel)->inchat) {
|
||||||
_sel = 0;
|
_sel = nullptr;
|
||||||
|
}
|
||||||
|
if (!_sel) {
|
||||||
if (!_byUsername.isEmpty()) {
|
if (!_byUsername.isEmpty()) {
|
||||||
if (_byUsernameSel < 0) _byUsernameSel = 0;
|
if (_byUsernameSel < 0) _byUsernameSel = 0;
|
||||||
for (; _byUsernameSel < _byUsername.size() && d_byUsername[_byUsernameSel]->inchat;) {
|
for (; _byUsernameSel < _byUsername.size() && d_byUsername[_byUsernameSel]->inchat;) {
|
||||||
|
@ -1169,10 +1112,13 @@ void ContactsInner::selectSkip(int32 dir) {
|
||||||
--_byUsernameSel;
|
--_byUsernameSel;
|
||||||
}
|
}
|
||||||
if (_byUsernameSel < 0) {
|
if (_byUsernameSel < 0) {
|
||||||
if (_contacts->list.count) {
|
if (!_contacts->isEmpty()) {
|
||||||
if (!_newItemSel && !_sel) _sel = _contacts->list.end->prev;
|
if (!_newItemSel && !_sel) _sel = *(_contacts->cend() - 1);
|
||||||
for (; _sel && contactData(_sel)->inchat;) {
|
for (auto i = _contacts->cfind(_sel), b = _contacts->cbegin(); i != b && contactData(*i)->inchat; --i) {
|
||||||
_sel = _sel->prev;
|
_sel = *i;
|
||||||
|
}
|
||||||
|
if (contactData(_sel)->inchat) {
|
||||||
|
_sel = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1180,9 +1126,9 @@ void ContactsInner::selectSkip(int32 dir) {
|
||||||
if (_newItemSel) {
|
if (_newItemSel) {
|
||||||
emit mustScrollTo(0, _newItemHeight);
|
emit mustScrollTo(0, _newItemHeight);
|
||||||
} else if (_sel) {
|
} else if (_sel) {
|
||||||
emit mustScrollTo(_newItemHeight + _sel->pos * _rowHeight, _newItemHeight + (_sel->pos + 1) * _rowHeight);
|
emit mustScrollTo(_newItemHeight + _sel->pos() * _rowHeight, _newItemHeight + (_sel->pos() + 1) * _rowHeight);
|
||||||
} else if (_byUsernameSel >= 0) {
|
} else if (_byUsernameSel >= 0) {
|
||||||
emit mustScrollTo(_newItemHeight + (_contacts->list.count + _byUsernameSel) * _rowHeight + st::searchedBarHeight, _newItemHeight + (_contacts->list.count + _byUsernameSel + 1) * _rowHeight + st::searchedBarHeight);
|
emit mustScrollTo(_newItemHeight + (_contacts->size() + _byUsernameSel) * _rowHeight + st::searchedBarHeight, _newItemHeight + (_contacts->size() + _byUsernameSel + 1) * _rowHeight + st::searchedBarHeight);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int cur = (_filteredSel >= 0) ? _filteredSel : ((_byUsernameSel >= 0) ? (_filtered.size() + _byUsernameSel) : -1);
|
int cur = (_filteredSel >= 0) ? _filteredSel : ((_byUsernameSel >= 0) ? (_filtered.size() + _byUsernameSel) : -1);
|
||||||
|
@ -1243,8 +1189,8 @@ void ContactsInner::selectSkipPage(int32 h, int32 dir) {
|
||||||
|
|
||||||
QVector<UserData*> ContactsInner::selected() {
|
QVector<UserData*> ContactsInner::selected() {
|
||||||
QVector<UserData*> result;
|
QVector<UserData*> result;
|
||||||
for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) {
|
for_const (auto row, *_contacts) {
|
||||||
if (_checkedContacts.contains(row->history->peer)) {
|
if (_checkedContacts.contains(row->history()->peer)) {
|
||||||
contactData(row); // fill _contactsData
|
contactData(row); // fill _contactsData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1264,8 +1210,8 @@ QVector<UserData*> ContactsInner::selected() {
|
||||||
|
|
||||||
QVector<MTPInputUser> ContactsInner::selectedInputs() {
|
QVector<MTPInputUser> ContactsInner::selectedInputs() {
|
||||||
QVector<MTPInputUser> result;
|
QVector<MTPInputUser> result;
|
||||||
for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) {
|
for_const (auto row, *_contacts) {
|
||||||
if (_checkedContacts.contains(row->history->peer)) {
|
if (_checkedContacts.contains(row->history()->peer)) {
|
||||||
contactData(row); // fill _contactsData
|
contactData(row); // fill _contactsData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1284,8 +1230,8 @@ QVector<MTPInputUser> ContactsInner::selectedInputs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
PeerData *ContactsInner::selectedUser() {
|
PeerData *ContactsInner::selectedUser() {
|
||||||
for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) {
|
for_const (auto row, *_contacts) {
|
||||||
if (_checkedContacts.contains(row->history->peer)) {
|
if (_checkedContacts.contains(row->history()->peer)) {
|
||||||
contactData(row); // fill _contactsData
|
contactData(row); // fill _contactsData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "abstractbox.h"
|
#include "abstractbox.h"
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
class Row;
|
||||||
|
class IndexedList;
|
||||||
|
} // namespace Dialogs
|
||||||
|
|
||||||
enum MembersFilter {
|
enum MembersFilter {
|
||||||
MembersFilterRecent,
|
MembersFilterRecent,
|
||||||
MembersFilterAdmins,
|
MembersFilterAdmins,
|
||||||
|
@ -69,7 +74,7 @@ public:
|
||||||
|
|
||||||
void loadProfilePhotos(int32 yFrom);
|
void loadProfilePhotos(int32 yFrom);
|
||||||
void chooseParticipant();
|
void chooseParticipant();
|
||||||
void changeCheckState(DialogRow *row);
|
void changeCheckState(Dialogs::Row *row);
|
||||||
void changeCheckState(ContactData *data, PeerData *peer);
|
void changeCheckState(ContactData *data, PeerData *peer);
|
||||||
|
|
||||||
void peopleReceived(const QString &query, const QVector<MTPPeer> &people);
|
void peopleReceived(const QString &query, const QVector<MTPPeer> &people);
|
||||||
|
@ -102,7 +107,7 @@ signals:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow);
|
void onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow);
|
||||||
|
|
||||||
void updateSel();
|
void updateSel();
|
||||||
void peerUpdated(PeerData *peer);
|
void peerUpdated(PeerData *peer);
|
||||||
|
@ -120,36 +125,38 @@ private:
|
||||||
void addAdminDone(const MTPUpdates &result, mtpRequestId req);
|
void addAdminDone(const MTPUpdates &result, mtpRequestId req);
|
||||||
bool addAdminFail(const RPCError &error, mtpRequestId req);
|
bool addAdminFail(const RPCError &error, mtpRequestId req);
|
||||||
|
|
||||||
int32 _rowHeight, _newItemHeight;
|
int32 _rowHeight;
|
||||||
bool _newItemSel;
|
int _newItemHeight = 0;
|
||||||
|
bool _newItemSel = false;
|
||||||
|
|
||||||
ChatData *_chat;
|
ChatData *_chat = nullptr;
|
||||||
ChannelData *_channel;
|
ChannelData *_channel = nullptr;
|
||||||
MembersFilter _membersFilter;
|
MembersFilter _membersFilter = MembersFilterRecent;
|
||||||
UserData *_bot;
|
UserData *_bot = nullptr;
|
||||||
CreatingGroupType _creating;
|
CreatingGroupType _creating = CreatingGroupNone;
|
||||||
MembersAlreadyIn _already;
|
MembersAlreadyIn _already;
|
||||||
|
|
||||||
Checkbox _allAdmins;
|
Checkbox _allAdmins;
|
||||||
int32 _aboutWidth;
|
int32 _aboutWidth;
|
||||||
Text _aboutAllAdmins, _aboutAdmins;
|
Text _aboutAllAdmins, _aboutAdmins;
|
||||||
|
|
||||||
PeerData *_addToPeer;
|
PeerData *_addToPeer = nullptr;
|
||||||
UserData *_addAdmin;
|
UserData *_addAdmin = nullptr;
|
||||||
mtpRequestId _addAdminRequestId;
|
mtpRequestId _addAdminRequestId = 0;
|
||||||
ConfirmBox *_addAdminBox;
|
ConfirmBox *_addAdminBox = nullptr;
|
||||||
|
|
||||||
int32 _time;
|
int32 _time;
|
||||||
|
|
||||||
DialogsIndexed *_contacts;
|
UniquePointer<Dialogs::IndexedList> _customList;
|
||||||
DialogRow *_sel;
|
Dialogs::IndexedList *_contacts = nullptr;
|
||||||
|
Dialogs::Row *_sel = nullptr;
|
||||||
QString _filter;
|
QString _filter;
|
||||||
typedef QVector<DialogRow*> FilteredDialogs;
|
typedef QVector<Dialogs::Row*> FilteredDialogs;
|
||||||
FilteredDialogs _filtered;
|
FilteredDialogs _filtered;
|
||||||
int32 _filteredSel;
|
int _filteredSel = -1;
|
||||||
bool _mouseSel;
|
bool _mouseSel = false;
|
||||||
|
|
||||||
int32 _selCount;
|
int _selCount = 0;
|
||||||
|
|
||||||
struct ContactData {
|
struct ContactData {
|
||||||
Text name;
|
Text name;
|
||||||
|
@ -163,22 +170,22 @@ private:
|
||||||
typedef QMap<PeerData*, bool> CheckedContacts;
|
typedef QMap<PeerData*, bool> CheckedContacts;
|
||||||
CheckedContacts _checkedContacts;
|
CheckedContacts _checkedContacts;
|
||||||
|
|
||||||
ContactData *contactData(DialogRow *row);
|
ContactData *contactData(Dialogs::Row *row);
|
||||||
|
|
||||||
bool _searching;
|
bool _searching = false;
|
||||||
QString _lastQuery;
|
QString _lastQuery;
|
||||||
typedef QVector<PeerData*> ByUsernameRows;
|
typedef QVector<PeerData*> ByUsernameRows;
|
||||||
typedef QVector<ContactData*> ByUsernameDatas;
|
typedef QVector<ContactData*> ByUsernameDatas;
|
||||||
ByUsernameRows _byUsername, _byUsernameFiltered;
|
ByUsernameRows _byUsername, _byUsernameFiltered;
|
||||||
ByUsernameDatas d_byUsername, d_byUsernameFiltered; // filtered is partly subset of d_byUsername, partly subset of _byUsernameDatas
|
ByUsernameDatas d_byUsername, d_byUsernameFiltered; // filtered is partly subset of d_byUsername, partly subset of _byUsernameDatas
|
||||||
ByUsernameDatas _byUsernameDatas;
|
ByUsernameDatas _byUsernameDatas;
|
||||||
int32 _byUsernameSel;
|
int _byUsernameSel = -1;
|
||||||
|
|
||||||
QPoint _lastMousePos;
|
QPoint _lastMousePos;
|
||||||
LinkButton _addContactLnk;
|
LinkButton _addContactLnk;
|
||||||
|
|
||||||
bool _saving;
|
bool _saving = false;
|
||||||
bool _allAdminsChecked;
|
bool _allAdminsChecked = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
|
||||||
|
class Row;
|
||||||
|
using RowsByLetter = QMap<QChar, Row*>;
|
||||||
|
|
||||||
|
enum class SortMode {
|
||||||
|
Date,
|
||||||
|
Name,
|
||||||
|
Add
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dialogs
|
|
@ -0,0 +1,164 @@
|
||||||
|
/*
|
||||||
|
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 "dialogs/dialogs_indexed_list.h"
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
|
||||||
|
IndexedList::IndexedList(SortMode sortMode)
|
||||||
|
: _sortMode(sortMode)
|
||||||
|
, _list(sortMode) {
|
||||||
|
}
|
||||||
|
|
||||||
|
RowsByLetter IndexedList::addToEnd(History *history) {
|
||||||
|
RowsByLetter result;
|
||||||
|
if (!_list.contains(history->peer->id)) {
|
||||||
|
result.insert(0, _list.addToEnd(history));
|
||||||
|
for_const (auto ch, history->peer->chars) {
|
||||||
|
auto j = _index.find(ch);
|
||||||
|
if (j == _index.cend()) {
|
||||||
|
j = _index.insert(ch, new List(_sortMode));
|
||||||
|
}
|
||||||
|
result.insert(ch, j.value()->addToEnd(history));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Row *IndexedList::addByName(History *history) {
|
||||||
|
if (auto row = _list.getRow(history->peer->id)) {
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
Row *result = _list.addByName(history);
|
||||||
|
for_const (auto ch, history->peer->chars) {
|
||||||
|
auto j = _index.find(ch);
|
||||||
|
if (j == _index.cend()) {
|
||||||
|
j = _index.insert(ch, new List(_sortMode));
|
||||||
|
}
|
||||||
|
j.value()->addByName(history);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IndexedList::adjustByPos(const RowsByLetter &links) {
|
||||||
|
for (auto i = links.cbegin(), e = links.cend(); i != e; ++i) {
|
||||||
|
if (i.key() == QChar(0)) {
|
||||||
|
_list.adjustByPos(i.value());
|
||||||
|
} else {
|
||||||
|
if (auto list = _index.value(i.key())) {
|
||||||
|
list->adjustByPos(i.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void IndexedList::peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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(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(ch, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IndexedList::del(const PeerData *peer, Row *replacedBy) {
|
||||||
|
if (_list.del(peer->id, replacedBy)) {
|
||||||
|
for_const (auto ch, peer->chars) {
|
||||||
|
if (auto list = _index.value(ch)) {
|
||||||
|
list->del(peer->id, replacedBy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IndexedList::clear() {
|
||||||
|
for_const (auto &list, _index) {
|
||||||
|
delete list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexedList::~IndexedList() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dialogs
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
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 "dialogs/dialogs_common.h"
|
||||||
|
#include "dialogs/dialogs_list.h"
|
||||||
|
|
||||||
|
class History;
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
|
||||||
|
class IndexedList {
|
||||||
|
public:
|
||||||
|
IndexedList(SortMode sortMode);
|
||||||
|
|
||||||
|
RowsByLetter addToEnd(History *history);
|
||||||
|
Row *addByName(History *history);
|
||||||
|
void adjustByPos(const RowsByLetter &links);
|
||||||
|
void peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
|
||||||
|
void del(const PeerData *peer, Row *replacedBy = nullptr);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
const List &all() const {
|
||||||
|
return _list;
|
||||||
|
}
|
||||||
|
const List *filtered(QChar ch) const {
|
||||||
|
static StaticNeverFreedPointer<List> empty(new List(SortMode::Add));
|
||||||
|
return _index.value(ch, empty.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
~IndexedList();
|
||||||
|
|
||||||
|
// Part of List interface is duplicated here for all() list.
|
||||||
|
int size() const { return all().size(); }
|
||||||
|
bool isEmpty() const { return all().isEmpty(); }
|
||||||
|
bool contains(PeerId peerId) const { return all().contains(peerId); }
|
||||||
|
Row *getRow(PeerId peerId) const { return all().getRow(peerId); }
|
||||||
|
Row *rowAtY(int32 y, int32 h) const { return all().rowAtY(y, h); }
|
||||||
|
|
||||||
|
using iterator = List::iterator;
|
||||||
|
using const_iterator = List::const_iterator;
|
||||||
|
const_iterator cbegin() const { return all().cbegin(); }
|
||||||
|
const_iterator cend() const { return all().cend(); }
|
||||||
|
const_iterator begin() const { return all().cbegin(); }
|
||||||
|
const_iterator end() const { return all().cend(); }
|
||||||
|
iterator begin() { return all().begin(); }
|
||||||
|
iterator end() { return all().end(); }
|
||||||
|
const_iterator cfind(Row *value) const { return all().cfind(value); }
|
||||||
|
const_iterator find(Row *value) const { return all().cfind(value); }
|
||||||
|
iterator find(Row *value) { return all().find(value); }
|
||||||
|
const_iterator cfind(int y, int h) const { return all().cfind(y, h); }
|
||||||
|
const_iterator find(int y, int h) const { return all().cfind(y, h); }
|
||||||
|
iterator find(int y, int h) { return all().find(y, h); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SortMode _sortMode;
|
||||||
|
List _list;
|
||||||
|
using Index = QMap<QChar, List*>;
|
||||||
|
Index _index;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dialogs
|
|
@ -0,0 +1,205 @@
|
||||||
|
/*
|
||||||
|
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 "dialogs/dialogs_layout.h"
|
||||||
|
|
||||||
|
#include "dialogs/dialogs_list.h"
|
||||||
|
#include "lang.h"
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
namespace Layout {
|
||||||
|
|
||||||
|
void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool selected, bool onlyBackground) {
|
||||||
|
QRect fullRect(0, 0, w, st::dlgHeight);
|
||||||
|
p.fillRect(fullRect, active ? st::dlgActiveBG : (selected ? st::dlgHoverBG : st::dlgBG));
|
||||||
|
if (onlyBackground) return;
|
||||||
|
|
||||||
|
History *history = row->history();
|
||||||
|
PeerData *userpicPeer = (history->peer->migrateTo() ? history->peer->migrateTo() : history->peer);
|
||||||
|
userpicPeer->paintUserpicLeft(p, st::dlgPhotoSize, st::dlgPaddingHor, st::dlgPaddingVer, w);
|
||||||
|
|
||||||
|
int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding;
|
||||||
|
int32 namewidth = w - nameleft - st::dlgPaddingHor;
|
||||||
|
QRect rectForName(nameleft, st::dlgPaddingVer + st::dlgNameTop, namewidth, st::msgNameFont->height);
|
||||||
|
|
||||||
|
// draw chat icon
|
||||||
|
if (history->peer->isChat() || history->peer->isMegagroup()) {
|
||||||
|
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 (history->peer->isChannel()) {
|
||||||
|
p.drawSprite(QPoint(rectForName.left() + st::dlgChannelImgPos.x(), rectForName.top() + st::dlgChannelImgPos.y()), (active ? st::dlgActiveChannelImg : st::dlgChannelImg));
|
||||||
|
rectForName.setLeft(rectForName.left() + st::dlgImgSkip);
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryItem *last = history->lastMsg;
|
||||||
|
if (!last) {
|
||||||
|
p.setFont(st::dlgHistFont);
|
||||||
|
p.setPen(active ? st::dlgActiveColor : st::dlgSystemColor);
|
||||||
|
if (history->typing.isEmpty() && history->sendActions.isEmpty()) {
|
||||||
|
p.drawText(nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgFont->ascent + st::dlgSep, lang(lng_empty_history));
|
||||||
|
} else {
|
||||||
|
history->typingText.drawElided(p, nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, namewidth);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// draw date
|
||||||
|
QDateTime now(QDateTime::currentDateTime()), lastTime(last->date);
|
||||||
|
QDate nowDate(now.date()), lastDate(lastTime.date());
|
||||||
|
QString dt;
|
||||||
|
if (lastDate == nowDate) {
|
||||||
|
dt = lastTime.toString(cTimeFormat());
|
||||||
|
} else if (lastDate.year() == nowDate.year() && lastDate.weekNumber() == nowDate.weekNumber()) {
|
||||||
|
dt = langDayOfWeek(lastDate);
|
||||||
|
} else {
|
||||||
|
dt = lastDate.toString(qsl("d.MM.yy"));
|
||||||
|
}
|
||||||
|
int32 dtWidth = st::dlgDateFont->width(dt);
|
||||||
|
rectForName.setWidth(rectForName.width() - dtWidth - st::dlgDateSkip);
|
||||||
|
p.setFont(st::dlgDateFont->f);
|
||||||
|
p.setPen((active ? st::dlgActiveDateColor : st::dlgDateColor)->p);
|
||||||
|
p.drawText(rectForName.left() + rectForName.width() + st::dlgDateSkip, rectForName.top() + st::msgNameFont->height - st::msgDateFont->descent, dt);
|
||||||
|
|
||||||
|
// draw check
|
||||||
|
if (last->needCheck()) {
|
||||||
|
const style::sprite *check;
|
||||||
|
if (last->id > 0) {
|
||||||
|
if (last->unread()) {
|
||||||
|
check = active ? &st::dlgActiveCheckImg : &st::dlgCheckImg;
|
||||||
|
} else {
|
||||||
|
check = active ? &st::dlgActiveDblCheckImg : &st::dlgDblCheckImg;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
check = active ? &st::dlgActiveSendImg : &st::dlgSendImg;
|
||||||
|
}
|
||||||
|
rectForName.setWidth(rectForName.width() - check->pxWidth() - st::dlgCheckSkip);
|
||||||
|
p.drawPixmap(QPoint(rectForName.left() + rectForName.width() + st::dlgCheckLeft, rectForName.top() + st::dlgCheckTop), App::sprite(), *check);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw unread
|
||||||
|
int32 lastWidth = namewidth, unread = history->unreadCount;
|
||||||
|
if (history->peer->migrateFrom()) {
|
||||||
|
if (History *h = App::historyLoaded(history->peer->migrateFrom()->id)) {
|
||||||
|
unread += h->unreadCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (unread) {
|
||||||
|
QString unreadStr = QString::number(unread);
|
||||||
|
int32 unreadWidth = st::dlgUnreadFont->width(unreadStr);
|
||||||
|
int32 unreadRectWidth = unreadWidth + 2 * st::dlgUnreadPaddingHor;
|
||||||
|
int32 unreadRectHeight = st::dlgUnreadFont->height + 2 * st::dlgUnreadPaddingVer;
|
||||||
|
int32 unreadRectLeft = w - st::dlgPaddingHor - unreadRectWidth;
|
||||||
|
int32 unreadRectTop = st::dlgHeight - st::dlgPaddingVer - unreadRectHeight;
|
||||||
|
lastWidth -= unreadRectWidth + st::dlgUnreadPaddingHor;
|
||||||
|
p.setBrush(active ? (history->mute ? st::dlgActiveUnreadMutedBG : st::dlgActiveUnreadBG) : (history->mute ? st::dlgUnreadMutedBG : st::dlgUnreadBG));
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.drawRoundedRect(unreadRectLeft, unreadRectTop, unreadRectWidth, unreadRectHeight, st::dlgUnreadRadius, st::dlgUnreadRadius);
|
||||||
|
p.setFont(st::dlgUnreadFont->f);
|
||||||
|
p.setPen(active ? st::dlgActiveUnreadColor : st::dlgUnreadColor);
|
||||||
|
p.drawText(unreadRectLeft + st::dlgUnreadPaddingHor, unreadRectTop + st::dlgUnreadPaddingVer + st::dlgUnreadFont->ascent, unreadStr);
|
||||||
|
}
|
||||||
|
if (history->typing.isEmpty() && history->sendActions.isEmpty()) {
|
||||||
|
last->drawInDialog(p, QRect(nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, lastWidth, st::dlgFont->height), active, history->textCachedFor, history->lastItemTextCache);
|
||||||
|
} else {
|
||||||
|
p.setPen(active ? st::dlgActiveColor : st::dlgSystemColor);
|
||||||
|
history->typingText.drawElided(p, nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, lastWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (history->peer->isUser() && history->peer->isVerified()) {
|
||||||
|
rectForName.setWidth(rectForName.width() - st::verifiedCheck.pxWidth() - st::verifiedCheckPos.x());
|
||||||
|
p.drawSprite(rectForName.topLeft() + QPoint(qMin(history->peer->dialogName().maxWidth(), rectForName.width()), 0) + st::verifiedCheckPos, (active ? st::verifiedCheckInv : st::verifiedCheck));
|
||||||
|
}
|
||||||
|
|
||||||
|
p.setPen(active ? st::dlgActiveColor : st::dlgNameColor);
|
||||||
|
history->peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RowPainter::paint(Painter &p, const FakeRow *row, int w, bool active, bool selected, bool onlyBackground) {
|
||||||
|
QRect fullRect(0, 0, w, st::dlgHeight);
|
||||||
|
p.fillRect(fullRect, (active ? st::dlgActiveBG : (selected ? st::dlgHoverBG : st::dlgBG))->b);
|
||||||
|
if (onlyBackground) return;
|
||||||
|
|
||||||
|
auto item = row->item();
|
||||||
|
auto history = item->history();
|
||||||
|
PeerData *userpicPeer = (history->peer->migrateTo() ? history->peer->migrateTo() : history->peer);
|
||||||
|
userpicPeer->paintUserpicLeft(p, st::dlgPhotoSize, st::dlgPaddingHor, st::dlgPaddingVer, w);
|
||||||
|
|
||||||
|
int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding;
|
||||||
|
int32 namewidth = w - nameleft - st::dlgPaddingHor;
|
||||||
|
QRect rectForName(nameleft, st::dlgPaddingVer + st::dlgNameTop, namewidth, st::msgNameFont->height);
|
||||||
|
|
||||||
|
// draw chat icon
|
||||||
|
if (history->peer->isChat() || history->peer->isMegagroup()) {
|
||||||
|
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 (history->peer->isChannel()) {
|
||||||
|
p.drawSprite(QPoint(rectForName.left() + st::dlgChannelImgPos.x(), rectForName.top() + st::dlgChannelImgPos.y()), (active ? st::dlgActiveChannelImg : st::dlgChannelImg));
|
||||||
|
rectForName.setLeft(rectForName.left() + st::dlgImgSkip);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw date
|
||||||
|
QDateTime now(QDateTime::currentDateTime()), lastTime(item->date);
|
||||||
|
QDate nowDate(now.date()), lastDate(lastTime.date());
|
||||||
|
QString dt;
|
||||||
|
if (lastDate == nowDate) {
|
||||||
|
dt = lastTime.toString(cTimeFormat());
|
||||||
|
} else if (lastDate.year() == nowDate.year() && lastDate.weekNumber() == nowDate.weekNumber()) {
|
||||||
|
dt = langDayOfWeek(lastDate);
|
||||||
|
} else {
|
||||||
|
dt = lastDate.toString(qsl("d.MM.yy"));
|
||||||
|
}
|
||||||
|
int32 dtWidth = st::dlgDateFont->width(dt);
|
||||||
|
rectForName.setWidth(rectForName.width() - dtWidth - st::dlgDateSkip);
|
||||||
|
p.setFont(st::dlgDateFont);
|
||||||
|
p.setPen(active ? st::dlgActiveDateColor : st::dlgDateColor);
|
||||||
|
p.drawText(rectForName.left() + rectForName.width() + st::dlgDateSkip, rectForName.top() + st::msgNameFont->height - st::msgDateFont->descent, dt);
|
||||||
|
|
||||||
|
// draw check
|
||||||
|
if (item->needCheck()) {
|
||||||
|
const style::sprite *check;
|
||||||
|
if (item->id > 0) {
|
||||||
|
if (item->unread()) {
|
||||||
|
check = active ? &st::dlgActiveCheckImg : &st::dlgCheckImg;
|
||||||
|
} else {
|
||||||
|
check = active ? &st::dlgActiveDblCheckImg : &st::dlgDblCheckImg;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
check = active ? &st::dlgActiveSendImg : &st::dlgSendImg;
|
||||||
|
}
|
||||||
|
rectForName.setWidth(rectForName.width() - check->pxWidth() - st::dlgCheckSkip);
|
||||||
|
p.drawSprite(QPoint(rectForName.left() + rectForName.width() + st::dlgCheckLeft, rectForName.top() + st::dlgCheckTop), *check);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw unread
|
||||||
|
int32 lastWidth = namewidth;
|
||||||
|
item->drawInDialog(p, QRect(nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, lastWidth, st::dlgFont->height), active, row->_cacheFor, row->_cache);
|
||||||
|
|
||||||
|
if (history->peer->isUser() && history->peer->isVerified()) {
|
||||||
|
rectForName.setWidth(rectForName.width() - st::verifiedCheck.pxWidth() - st::verifiedCheckPos.x());
|
||||||
|
p.drawSprite(rectForName.topLeft() + QPoint(qMin(history->peer->dialogName().maxWidth(), rectForName.width()), 0) + st::verifiedCheckPos, (active ? st::verifiedCheckInv : st::verifiedCheck));
|
||||||
|
}
|
||||||
|
|
||||||
|
p.setPen(active ? st::dlgActiveColor : st::dlgNameColor);
|
||||||
|
history->peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Layout
|
||||||
|
} // namespace Dialogs
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
|
||||||
|
class Row;
|
||||||
|
class FakeRow;
|
||||||
|
|
||||||
|
namespace Layout {
|
||||||
|
|
||||||
|
class RowPainter {
|
||||||
|
public:
|
||||||
|
static void paint(Painter &p, const Row *row, int w, bool active, bool selected, bool onlyBackground);
|
||||||
|
static void paint(Painter &p, const FakeRow *row, int w, bool active, bool selected, bool onlyBackground);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Layout
|
||||||
|
} // namespace Dialogs
|
|
@ -0,0 +1,239 @@
|
||||||
|
/*
|
||||||
|
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 "dialogs/dialogs_list.h"
|
||||||
|
|
||||||
|
#include "dialogs/dialogs_layout.h"
|
||||||
|
#include "mainwidget.h"
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
|
||||||
|
List::List(SortMode sortMode)
|
||||||
|
: _last(MakeUnique<Row>(nullptr, nullptr, nullptr, 0))
|
||||||
|
, _begin(_last.data())
|
||||||
|
, _end(_last.data())
|
||||||
|
, _sortMode(sortMode)
|
||||||
|
, _current(_last.data()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::adjustCurrent(int32 y, int32 h) const {
|
||||||
|
if (isEmpty()) return;
|
||||||
|
|
||||||
|
int32 pos = (y > 0) ? (y / h) : 0;
|
||||||
|
while (_current->_pos > pos && _current != _begin) {
|
||||||
|
_current = _current->_prev;
|
||||||
|
}
|
||||||
|
while (_current->_pos + 1 <= pos && _current->_next != _end) {
|
||||||
|
_current = _current->_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::paint(Painter &p, int32 w, int32 hFrom, int32 hTo, PeerData *act, PeerData *sel, bool onlyBackground) const {
|
||||||
|
adjustCurrent(hFrom, st::dlgHeight);
|
||||||
|
|
||||||
|
Row *row = _current;
|
||||||
|
p.translate(0, row->_pos * st::dlgHeight);
|
||||||
|
while (row != _end && row->_pos * st::dlgHeight < hTo) {
|
||||||
|
bool active = (row->history()->peer == act) || (row->history()->peer->migrateTo() && row->history()->peer->migrateTo() == act);
|
||||||
|
bool selected = (row->history()->peer == sel);
|
||||||
|
Layout::RowPainter::paint(p, row, w, active, selected, onlyBackground);
|
||||||
|
row = row->_next;
|
||||||
|
p.translate(0, st::dlgHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row *List::addToEnd(History *history) {
|
||||||
|
Row *result = new Row(history, _end->_prev, _end, _end->_pos);
|
||||||
|
_end->_pos++;
|
||||||
|
if (_begin == _end) {
|
||||||
|
_begin = _current = result;
|
||||||
|
} else {
|
||||||
|
_end->_prev->_next = result;
|
||||||
|
}
|
||||||
|
_rowByPeer.insert(history->peer->id, result);
|
||||||
|
++_count;
|
||||||
|
_end->_prev = result;
|
||||||
|
if (_sortMode == SortMode::Date) {
|
||||||
|
adjustByPos(result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool List::insertBefore(Row *row, Row *before) {
|
||||||
|
if (row == before) return false;
|
||||||
|
|
||||||
|
if (_current == row) {
|
||||||
|
_current = row->_prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
Row *updateTill = row->_prev;
|
||||||
|
remove(row);
|
||||||
|
|
||||||
|
// insert row
|
||||||
|
row->_next = before; // update row
|
||||||
|
row->_prev = before->_prev;
|
||||||
|
row->_next->_prev = row; // update row->next
|
||||||
|
if (row->_prev) { // update row->prev
|
||||||
|
row->_prev->_next = row;
|
||||||
|
} else {
|
||||||
|
_begin = row;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update y
|
||||||
|
for (Row *n = row; n != updateTill; n = n->_next) {
|
||||||
|
n->_next->_pos++;
|
||||||
|
row->_pos--;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool List::insertAfter(Row *row, Row *after) {
|
||||||
|
if (row == after) return false;
|
||||||
|
|
||||||
|
if (_current == row) {
|
||||||
|
_current = row->_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Row *updateFrom = row->_next;
|
||||||
|
remove(row);
|
||||||
|
|
||||||
|
// insert row
|
||||||
|
row->_prev = after; // update row
|
||||||
|
row->_next = after->_next;
|
||||||
|
row->_prev->_next = row; // update row->prev
|
||||||
|
row->_next->_prev = row; // update row->next
|
||||||
|
|
||||||
|
// update y
|
||||||
|
for (Row *n = updateFrom; n != row; n = n->_next) {
|
||||||
|
n->_pos--;
|
||||||
|
row->_pos++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Row *List::adjustByName(const PeerData *peer) {
|
||||||
|
if (_sortMode != SortMode::Name) return nullptr;
|
||||||
|
|
||||||
|
auto i = _rowByPeer.find(peer->id);
|
||||||
|
if (i == _rowByPeer.cend()) return nullptr;
|
||||||
|
|
||||||
|
Row *row = i.value(), *change = row;
|
||||||
|
while (change->_prev && change->_prev->history()->peer->name > peer->name) {
|
||||||
|
change = change->_prev;
|
||||||
|
}
|
||||||
|
if (!insertBefore(row, change)) {
|
||||||
|
while (change->_next != _end && change->_next->history()->peer->name < peer->name) {
|
||||||
|
change = change->_next;
|
||||||
|
}
|
||||||
|
insertAfter(row, change);
|
||||||
|
}
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
Row *List::addByName(History *history) {
|
||||||
|
if (_sortMode != SortMode::Name) return nullptr;
|
||||||
|
|
||||||
|
Row *row = addToEnd(history), *change = row;
|
||||||
|
const QString &peerName(history->peer->name);
|
||||||
|
while (change->_prev && change->_prev->history()->peer->name.compare(peerName, Qt::CaseInsensitive) > 0) {
|
||||||
|
change = change->_prev;
|
||||||
|
}
|
||||||
|
if (!insertBefore(row, change)) {
|
||||||
|
while (change->_next != _end && change->_next->history()->peer->name.compare(peerName, Qt::CaseInsensitive) < 0) {
|
||||||
|
change = change->_next;
|
||||||
|
}
|
||||||
|
insertAfter(row, change);
|
||||||
|
}
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::adjustByPos(Row *row) {
|
||||||
|
if (_sortMode != SortMode::Date || !_begin) return;
|
||||||
|
|
||||||
|
Row *change = row;
|
||||||
|
if (change != _begin && _begin->history()->sortKeyInChatList() < row->history()->sortKeyInChatList()) {
|
||||||
|
change = _begin;
|
||||||
|
} else {
|
||||||
|
while (change->_prev && change->_prev->history()->sortKeyInChatList() < row->history()->sortKeyInChatList()) {
|
||||||
|
change = change->_prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!insertBefore(row, change)) {
|
||||||
|
if (change->_next != _end && _end->_prev->history()->sortKeyInChatList() > row->history()->sortKeyInChatList()) {
|
||||||
|
change = _end->_prev;
|
||||||
|
} else {
|
||||||
|
while (change->_next != _end && change->_next->history()->sortKeyInChatList() > row->history()->sortKeyInChatList()) {
|
||||||
|
change = change->_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
insertAfter(row, change);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool List::del(PeerId peerId, Row *replacedBy) {
|
||||||
|
auto i = _rowByPeer.find(peerId);
|
||||||
|
if (i == _rowByPeer.cend()) return false;
|
||||||
|
|
||||||
|
Row *row = i.value();
|
||||||
|
if (App::main()) {
|
||||||
|
emit App::main()->dialogRowReplaced(row, replacedBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row == _current) {
|
||||||
|
_current = row->_next;
|
||||||
|
}
|
||||||
|
for (Row *change = row->_next; change != _end; change = change->_next) {
|
||||||
|
--change->_pos;
|
||||||
|
}
|
||||||
|
--_end->_pos;
|
||||||
|
remove(row);
|
||||||
|
delete row;
|
||||||
|
--_count;
|
||||||
|
_rowByPeer.erase(i);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::remove(Row *row) {
|
||||||
|
row->_next->_prev = row->_prev; // update row->next
|
||||||
|
if (row->_prev) { // update row->prev
|
||||||
|
row->_prev->_next = row->_next;
|
||||||
|
} else {
|
||||||
|
_begin = row->_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::clear() {
|
||||||
|
while (_begin != _end) {
|
||||||
|
_current = _begin;
|
||||||
|
_begin = _begin->_next;
|
||||||
|
delete _current;
|
||||||
|
}
|
||||||
|
_current = _begin;
|
||||||
|
_rowByPeer.clear();
|
||||||
|
_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
List::~List() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dialogs
|
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
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 "dialogs/dialogs_row.h"
|
||||||
|
|
||||||
|
class PeerData;
|
||||||
|
namespace Dialogs {
|
||||||
|
|
||||||
|
class List {
|
||||||
|
public:
|
||||||
|
List(SortMode sortMode);
|
||||||
|
List(const List &other) = delete;
|
||||||
|
List &operator=(const List &other) = delete;
|
||||||
|
|
||||||
|
int size() const {
|
||||||
|
return _count;
|
||||||
|
}
|
||||||
|
bool isEmpty() const {
|
||||||
|
return size() == 0;
|
||||||
|
}
|
||||||
|
bool contains(PeerId peerId) const {
|
||||||
|
return _rowByPeer.contains(peerId);
|
||||||
|
}
|
||||||
|
Row *getRow(PeerId peerId) const {
|
||||||
|
return _rowByPeer.value(peerId);
|
||||||
|
}
|
||||||
|
Row *rowAtY(int32 y, int32 h) const {
|
||||||
|
auto i = cfind(y, h);
|
||||||
|
if (i == cend() || (*i)->pos() != ((y > 0) ? (y / h) : 0)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return *i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void paint(Painter &p, int32 w, int32 hFrom, int32 hTo, PeerData *act, PeerData *sel, bool onlyBackground) const;
|
||||||
|
Row *addToEnd(History *history);
|
||||||
|
bool insertBefore(Row *row, Row *before);
|
||||||
|
bool insertAfter(Row *row, Row *after);
|
||||||
|
Row *adjustByName(const PeerData *peer);
|
||||||
|
Row *addByName(History *history);
|
||||||
|
void adjustByPos(Row *row);
|
||||||
|
bool del(PeerId peerId, Row *replacedBy = nullptr);
|
||||||
|
void remove(Row *row);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
class const_iterator {
|
||||||
|
public:
|
||||||
|
using value_type = Row*;
|
||||||
|
using pointer = Row**;
|
||||||
|
using reference = Row*&;
|
||||||
|
|
||||||
|
explicit const_iterator(Row *p) : _p(p) {
|
||||||
|
}
|
||||||
|
inline Row* operator*() const { return _p; }
|
||||||
|
inline Row* const* operator->() const { return &_p; }
|
||||||
|
inline bool operator==(const const_iterator &other) const { return _p == other._p; }
|
||||||
|
inline bool operator!=(const const_iterator &other) const { return !(*this == other); }
|
||||||
|
inline const_iterator &operator++() { _p = next(_p); return *this; }
|
||||||
|
inline const_iterator operator++(int) { const_iterator result(*this); ++(*this); return result; }
|
||||||
|
inline const_iterator &operator--() { _p = prev(_p); return *this; }
|
||||||
|
inline const_iterator operator--(int) { const_iterator result(*this); --(*this); return result; }
|
||||||
|
inline const_iterator operator+(int j) const { const_iterator result = *this; return result += j; }
|
||||||
|
inline const_iterator operator-(int j) const { const_iterator result = *this; return result -= j; }
|
||||||
|
inline const_iterator &operator+=(int j) { if (j < 0) return (*this -= (-j)); while (j--) ++*this; return *this; }
|
||||||
|
inline const_iterator &operator-=(int j) { if (j < 0) return (*this += (-j)); while (j--) --*this; return *this; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Row *_p;
|
||||||
|
friend class List;
|
||||||
|
|
||||||
|
};
|
||||||
|
friend class const_iterator;
|
||||||
|
using iterator = const_iterator;
|
||||||
|
|
||||||
|
const_iterator cbegin() const { return const_iterator(_begin); }
|
||||||
|
const_iterator cend() const { return const_iterator(_end); }
|
||||||
|
const_iterator begin() const { return cbegin(); }
|
||||||
|
const_iterator end() const { return cend(); }
|
||||||
|
iterator begin() { return iterator(_begin); }
|
||||||
|
iterator end() { return iterator(_end); }
|
||||||
|
const_iterator cfind(Row *value) const { return value ? const_iterator(value) : cend(); }
|
||||||
|
const_iterator find(Row *value) const { return cfind(value); }
|
||||||
|
iterator find(Row *value) { return value ? iterator(value) : end(); }
|
||||||
|
const_iterator cfind(int y, int h) const {
|
||||||
|
adjustCurrent(y, h);
|
||||||
|
return iterator(_current);
|
||||||
|
}
|
||||||
|
const_iterator find(int y, int h) const { return cfind(y, h); }
|
||||||
|
iterator find(int y, int h) {
|
||||||
|
adjustCurrent(y, h);
|
||||||
|
return iterator(_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
~List();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void adjustCurrent(int y, int h) const;
|
||||||
|
static Row *next(Row *row) {
|
||||||
|
return row->_next;
|
||||||
|
}
|
||||||
|
static Row *prev(Row *row) {
|
||||||
|
return row->_prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
UniquePointer<Row> _last;
|
||||||
|
Row *_begin;
|
||||||
|
Row *_end;
|
||||||
|
SortMode _sortMode;
|
||||||
|
int _count = 0;
|
||||||
|
|
||||||
|
typedef QHash<PeerId, Row*> RowByPeer;
|
||||||
|
RowByPeer _rowByPeer;
|
||||||
|
|
||||||
|
mutable Row *_current; // cache
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dialogs
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
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/text.h"
|
||||||
|
|
||||||
|
class History;
|
||||||
|
class HistoryItem;
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
namespace Layout {
|
||||||
|
class RowPainter;
|
||||||
|
} // namespace Layout
|
||||||
|
|
||||||
|
class List;
|
||||||
|
class Row {
|
||||||
|
public:
|
||||||
|
Row(History *history, Row *prev, Row *next, int pos)
|
||||||
|
: _history(history)
|
||||||
|
, _prev(prev)
|
||||||
|
, _next(next)
|
||||||
|
, _pos(pos) {
|
||||||
|
}
|
||||||
|
void *attached = nullptr; // for any attached data, for example View in contacts list
|
||||||
|
|
||||||
|
History *history() const {
|
||||||
|
return _history;
|
||||||
|
}
|
||||||
|
int pos() const {
|
||||||
|
return _pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class List;
|
||||||
|
|
||||||
|
History *_history;
|
||||||
|
Row *_prev, *_next;
|
||||||
|
int _pos;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class FakeRow {
|
||||||
|
public:
|
||||||
|
FakeRow(HistoryItem *item) : _item(item) {
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryItem *item() const {
|
||||||
|
return _item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class Layout::RowPainter;
|
||||||
|
|
||||||
|
HistoryItem *_item;
|
||||||
|
mutable const HistoryItem *_cacheFor = nullptr;
|
||||||
|
mutable Text _cache = Text{ int(st::dlgRichMinWidth) };
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dialogs
|
|
@ -19,9 +19,12 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
#include "dialogswidget.h"
|
||||||
|
|
||||||
|
#include "dialogs/dialogs_indexed_list.h"
|
||||||
|
#include "dialogs/dialogs_layout.h"
|
||||||
#include "ui/style.h"
|
#include "ui/style.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
|
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "dialogswidget.h"
|
#include "dialogswidget.h"
|
||||||
|
@ -29,39 +32,18 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "boxes/addcontactbox.h"
|
#include "boxes/addcontactbox.h"
|
||||||
#include "boxes/contactsbox.h"
|
#include "boxes/contactsbox.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
|
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
|
|
||||||
DialogsInner::DialogsInner(QWidget *parent, MainWidget *main) : SplittedWidget(parent)
|
DialogsInner::DialogsInner(QWidget *parent, MainWidget *main) : SplittedWidget(parent)
|
||||||
, dialogs(DialogsSortByDate)
|
, dialogs(MakeUnique<Dialogs::IndexedList>(Dialogs::SortMode::Date))
|
||||||
, contactsNoDialogs(DialogsSortByName)
|
, contactsNoDialogs(MakeUnique<Dialogs::IndexedList>(Dialogs::SortMode::Name))
|
||||||
, contacts(DialogsSortByName)
|
, contacts(MakeUnique<Dialogs::IndexedList>(Dialogs::SortMode::Name))
|
||||||
, sel(0)
|
|
||||||
, contactSel(false)
|
|
||||||
, selByMouse(false)
|
|
||||||
, _hashtagSel(-1)
|
|
||||||
, _filteredSel(-1)
|
|
||||||
, _searchedCount(0)
|
|
||||||
, _searchedMigratedCount(0)
|
|
||||||
, _searchedSel(-1)
|
|
||||||
, _peopleSel(-1)
|
|
||||||
, _lastSearchDate(0)
|
|
||||||
, _lastSearchPeer(0)
|
|
||||||
, _lastSearchId(0)
|
|
||||||
, _lastSearchMigratedId(0)
|
|
||||||
, _state(DefaultState)
|
|
||||||
, _addContactLnk(this, lang(lng_add_contact_button))
|
, _addContactLnk(this, lang(lng_add_contact_button))
|
||||||
, _cancelSearchInPeer(this, st::btnCancelSearch)
|
, _cancelSearchInPeer(this, st::btnCancelSearch) {
|
||||||
, _overDelete(false)
|
|
||||||
, _searchInPeer(0)
|
|
||||||
, _searchInMigrated(0)
|
|
||||||
, _menuPeer(0)
|
|
||||||
, _menuActionPeer(0)
|
|
||||||
, _menu(0) {
|
|
||||||
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
|
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(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*)));
|
connect(main, SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(onPeerPhotoChanged(PeerData*)));
|
||||||
connect(main, SIGNAL(dialogRowReplaced(DialogRow*,DialogRow*)), this, SLOT(onDialogRowReplaced(DialogRow*,DialogRow*)));
|
connect(main, SIGNAL(dialogRowReplaced(Dialogs::Row*,Dialogs::Row*)), this, SLOT(onDialogRowReplaced(Dialogs::Row*,Dialogs::Row*)));
|
||||||
connect(&_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact()));
|
connect(&_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact()));
|
||||||
connect(&_cancelSearchInPeer, SIGNAL(clicked()), this, SIGNAL(cancelSearchInPeer()));
|
connect(&_cancelSearchInPeer, SIGNAL(clicked()), this, SIGNAL(cancelSearchInPeer()));
|
||||||
_cancelSearchInPeer.hide();
|
_cancelSearchInPeer.hide();
|
||||||
|
@ -94,14 +76,12 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_state == DefaultState) {
|
if (_state == DefaultState) {
|
||||||
int32 otherStart = dialogs.list.count * st::dlgHeight;
|
int32 otherStart = dialogs->size() * st::dlgHeight;
|
||||||
PeerData *active = App::main()->activePeer(), *selected = _menuPeer ? _menuPeer : (sel ? sel->history->peer : 0);
|
PeerData *active = App::main()->activePeer(), *selected = _menuPeer ? _menuPeer : (sel ? sel->history()->peer : 0);
|
||||||
if (otherStart) {
|
if (otherStart) {
|
||||||
dialogs.list.paint(p, fullWidth(), r.top(), r.top() + r.height(), active, selected, paintingOther);
|
dialogs->all().paint(p, fullWidth(), r.top(), r.top() + r.height(), active, selected, paintingOther);
|
||||||
}
|
}
|
||||||
if (contactsNoDialogs.list.count && false) {
|
if (!otherStart) {
|
||||||
contactsNoDialogs.list.paint(p, fullWidth(), r.top() - otherStart, r.top() + r.height() - otherStart, active, selected, paintingOther);
|
|
||||||
} else if (!otherStart) {
|
|
||||||
p.fillRect(r, st::white->b);
|
p.fillRect(r, st::white->b);
|
||||||
if (!paintingOther) {
|
if (!paintingOther) {
|
||||||
p.setFont(st::noContactsFont->f);
|
p.setFont(st::noContactsFont->f);
|
||||||
|
@ -163,9 +143,9 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO
|
||||||
PeerData *act = App::main()->activePeer();
|
PeerData *act = App::main()->activePeer();
|
||||||
MsgId actId = App::main()->activeMsgId();
|
MsgId actId = App::main()->activeMsgId();
|
||||||
for (; from < to; ++from) {
|
for (; from < to; ++from) {
|
||||||
bool active = ((_filterResults[from]->history->peer == act) || (_filterResults[from]->history->peer->migrateTo() && _filterResults[from]->history->peer->migrateTo() == act)) && !actId;
|
bool active = ((_filterResults[from]->history()->peer == act) || (_filterResults[from]->history()->peer->migrateTo() && _filterResults[from]->history()->peer->migrateTo() == act)) && !actId;
|
||||||
bool selected = (from == _filteredSel) || (_filterResults[from]->history->peer == _menuPeer);
|
bool selected = (from == _filteredSel) || (_filterResults[from]->history()->peer == _menuPeer);
|
||||||
_filterResults[from]->paint(p, w, active, selected, paintingOther);
|
Dialogs::Layout::RowPainter::paint(p, _filterResults[from], w, active, selected, paintingOther);
|
||||||
p.translate(0, st::dlgHeight);
|
p.translate(0, st::dlgHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,9 +210,12 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO
|
||||||
PeerData *act = App::main()->activePeer();
|
PeerData *act = App::main()->activePeer();
|
||||||
MsgId actId = App::main()->activeMsgId();
|
MsgId actId = App::main()->activeMsgId();
|
||||||
for (; from < to; ++from) {
|
for (; from < to; ++from) {
|
||||||
bool active = (_searchResults[from]->_item->history()->peer == act && _searchResults[from]->_item->id == actId) || (_searchResults[from]->_item->history()->peer->migrateTo() && _searchResults[from]->_item->history()->peer->migrateTo() == act && _searchResults[from]->_item->id == -actId);
|
auto result = _searchResults[from];
|
||||||
|
auto item = result->item();
|
||||||
|
auto history = item->history();
|
||||||
|
bool active = (history->peer == act && item->id == actId) || (history->peer->migrateTo() && history->peer->migrateTo() == act && item->id == -actId);
|
||||||
bool selected = (from == _searchedSel);
|
bool selected = (from == _searchedSel);
|
||||||
_searchResults[from]->paint(p, w, active, selected, paintingOther);
|
Dialogs::Layout::RowPainter::paint(p, result, w, active, selected, paintingOther);
|
||||||
p.translate(0, st::dlgHeight);
|
p.translate(0, st::dlgHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -336,14 +319,8 @@ void DialogsInner::onUpdateSelected(bool force) {
|
||||||
int w = width(), mouseY = mouse.y();
|
int w = width(), mouseY = mouse.y();
|
||||||
_overDelete = false;
|
_overDelete = false;
|
||||||
if (_state == DefaultState) {
|
if (_state == DefaultState) {
|
||||||
DialogRow *newSel = dialogs.list.rowAtY(mouseY, st::dlgHeight);
|
auto newSel = dialogs->rowAtY(mouseY, st::dlgHeight);
|
||||||
int32 otherStart = dialogs.list.count * st::dlgHeight;
|
int otherStart = dialogs->size() * st::dlgHeight;
|
||||||
if (newSel) {
|
|
||||||
contactSel = false;
|
|
||||||
} else {
|
|
||||||
newSel = 0;// contactsNoDialogs.list.rowAtY(mouseY - otherStart, st::dlgHeight);
|
|
||||||
contactSel = true;
|
|
||||||
}
|
|
||||||
if (newSel != sel) {
|
if (newSel != sel) {
|
||||||
updateSelectedRow();
|
updateSelectedRow();
|
||||||
sel = newSel;
|
sel = newSel;
|
||||||
|
@ -419,7 +396,7 @@ void DialogsInner::resizeEvent(QResizeEvent *e) {
|
||||||
_cancelSearchInPeer.move(width() - st::dlgPaddingHor - st::btnCancelSearch.width, (st::dlgHeight - st::btnCancelSearch.height) / 2);
|
_cancelSearchInPeer.move(width() - st::dlgPaddingHor - st::btnCancelSearch.width, (st::dlgHeight - st::btnCancelSearch.height) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogsInner::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) {
|
void DialogsInner::onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow) {
|
||||||
if (_state == FilteredState || _state == SearchedState) {
|
if (_state == FilteredState || _state == SearchedState) {
|
||||||
for (FilteredDialogs::iterator i = _filterResults.begin(); i != _filterResults.end();) {
|
for (FilteredDialogs::iterator i = _filterResults.begin(); i != _filterResults.end();) {
|
||||||
if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts!
|
if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts!
|
||||||
|
@ -442,10 +419,10 @@ void DialogsInner::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) {
|
||||||
void DialogsInner::createDialog(History *history) {
|
void DialogsInner::createDialog(History *history) {
|
||||||
bool creating = !history->inChatList();
|
bool creating = !history->inChatList();
|
||||||
if (creating) {
|
if (creating) {
|
||||||
DialogRow *mainRow = history->addToChatList(dialogs);
|
Dialogs::Row *mainRow = history->addToChatList(dialogs.data());
|
||||||
contactsNoDialogs.del(history->peer, mainRow);
|
contactsNoDialogs->del(history->peer, mainRow);
|
||||||
}
|
}
|
||||||
RefPair(int32, movedFrom, int32, movedTo) = history->adjustByPosInChatsList(dialogs);
|
RefPair(int32, movedFrom, int32, movedTo) = history->adjustByPosInChatsList(dialogs.data());
|
||||||
|
|
||||||
emit dialogMoved(movedFrom, movedTo);
|
emit dialogMoved(movedFrom, movedTo);
|
||||||
|
|
||||||
|
@ -461,15 +438,15 @@ void DialogsInner::removeDialog(History *history) {
|
||||||
if (history->peer == _menuPeer && _menu) {
|
if (history->peer == _menuPeer && _menu) {
|
||||||
_menu->deleteLater();
|
_menu->deleteLater();
|
||||||
}
|
}
|
||||||
if (sel && sel->history == history) {
|
if (sel && sel->history() == history) {
|
||||||
sel = 0;
|
sel = nullptr;
|
||||||
}
|
}
|
||||||
history->removeFromChatList(dialogs);
|
history->removeFromChatList(dialogs.data());
|
||||||
history->clearNotifications();
|
history->clearNotifications();
|
||||||
if (App::wnd()) App::wnd()->notifyClear(history);
|
if (App::wnd()) App::wnd()->notifyClear(history);
|
||||||
if (contacts.list.rowByPeer.constFind(history->peer->id) != contacts.list.rowByPeer.cend()) {
|
if (contacts->contains(history->peer->id)) {
|
||||||
if (contactsNoDialogs.list.rowByPeer.constFind(history->peer->id) == contactsNoDialogs.list.rowByPeer.cend()) {
|
if (!contactsNoDialogs->contains(history->peer->id)) {
|
||||||
contactsNoDialogs.addByName(history);
|
contactsNoDialogs->addByName(history);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,12 +457,12 @@ void DialogsInner::removeDialog(History *history) {
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogsInner::dlgUpdated(DialogRow *row) {
|
void DialogsInner::dlgUpdated(Dialogs::Row *row) {
|
||||||
if (_state == DefaultState) {
|
if (_state == DefaultState) {
|
||||||
update(0, row->pos * st::dlgHeight, fullWidth(), st::dlgHeight);
|
update(0, row->pos() * st::dlgHeight, fullWidth(), st::dlgHeight);
|
||||||
} else if (_state == FilteredState || _state == SearchedState) {
|
} else if (_state == FilteredState || _state == SearchedState) {
|
||||||
for (int32 i = 0, l = _filterResults.size(); i < l; ++i) {
|
for (int32 i = 0, l = _filterResults.size(); i < l; ++i) {
|
||||||
if (_filterResults.at(i)->history == row->history) {
|
if (_filterResults.at(i)->history() == row->history()) {
|
||||||
update(0, i * st::dlgHeight, fullWidth(), st::dlgHeight);
|
update(0, i * st::dlgHeight, fullWidth(), st::dlgHeight);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -495,15 +472,13 @@ void DialogsInner::dlgUpdated(DialogRow *row) {
|
||||||
|
|
||||||
void DialogsInner::dlgUpdated(History *history, MsgId msgId) {
|
void DialogsInner::dlgUpdated(History *history, MsgId msgId) {
|
||||||
if (_state == DefaultState) {
|
if (_state == DefaultState) {
|
||||||
DialogRow *row = 0;
|
if (auto row = dialogs->getRow(history->peer->id)) {
|
||||||
DialogsList::RowByPeer::iterator i = dialogs.list.rowByPeer.find(history->peer->id);
|
update(0, row->pos() * st::dlgHeight, fullWidth(), st::dlgHeight);
|
||||||
if (i != dialogs.list.rowByPeer.cend()) {
|
|
||||||
update(0, i.value()->pos * st::dlgHeight, fullWidth(), st::dlgHeight);
|
|
||||||
}
|
}
|
||||||
} else if (_state == FilteredState || _state == SearchedState) {
|
} else if (_state == FilteredState || _state == SearchedState) {
|
||||||
int32 cnt = 0, add = filteredOffset();
|
int32 cnt = 0, add = filteredOffset();
|
||||||
for (FilteredDialogs::const_iterator i = _filterResults.cbegin(), e = _filterResults.cend(); i != e; ++i) {
|
for (FilteredDialogs::const_iterator i = _filterResults.cbegin(), e = _filterResults.cend(); i != e; ++i) {
|
||||||
if ((*i)->history == history) {
|
if ((*i)->history() == history) {
|
||||||
update(0, add + cnt * st::dlgHeight, fullWidth(), st::dlgHeight);
|
update(0, add + cnt * st::dlgHeight, fullWidth(), st::dlgHeight);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -522,7 +497,7 @@ void DialogsInner::dlgUpdated(History *history, MsgId msgId) {
|
||||||
if (!_searchResults.isEmpty()) {
|
if (!_searchResults.isEmpty()) {
|
||||||
int32 cnt = 0, add = searchedOffset();
|
int32 cnt = 0, add = searchedOffset();
|
||||||
for (SearchResults::const_iterator i = _searchResults.cbegin(), e = _searchResults.cend(); i != e; ++i) {
|
for (SearchResults::const_iterator i = _searchResults.cbegin(), e = _searchResults.cend(); i != e; ++i) {
|
||||||
if ((*i)->_item->history() == history && (*i)->_item->id == msgId) {
|
if ((*i)->item()->history() == history && (*i)->item()->id == msgId) {
|
||||||
update(0, add + cnt * st::dlgHeight, fullWidth(), st::dlgHeight);
|
update(0, add + cnt * st::dlgHeight, fullWidth(), st::dlgHeight);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -547,12 +522,12 @@ void DialogsInner::updateSelectedRow(PeerData *peer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (sel) {
|
} else if (sel) {
|
||||||
update(0, sel->pos * st::dlgHeight, fullWidth(), st::dlgHeight);
|
update(0, sel->pos() * st::dlgHeight, fullWidth(), st::dlgHeight);
|
||||||
}
|
}
|
||||||
} else if (_state == FilteredState || _state == SearchedState) {
|
} else if (_state == FilteredState || _state == SearchedState) {
|
||||||
if (peer) {
|
if (peer) {
|
||||||
for (int32 i = 0, l = _filterResults.size(); i != l; ++i) {
|
for (int32 i = 0, l = _filterResults.size(); i != l; ++i) {
|
||||||
if (_filterResults.at(i)->history->peer == peer) {
|
if (_filterResults.at(i)->history()->peer == peer) {
|
||||||
update(0, filteredOffset() + i * st::dlgHeight, fullWidth(), st::dlgHeight);
|
update(0, filteredOffset() + i * st::dlgHeight, fullWidth(), st::dlgHeight);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -600,10 +575,10 @@ void DialogsInner::contextMenuEvent(QContextMenuEvent *e) {
|
||||||
|
|
||||||
History *history = 0;
|
History *history = 0;
|
||||||
if (_state == DefaultState) {
|
if (_state == DefaultState) {
|
||||||
if (sel) history = sel->history;
|
if (sel) history = sel->history();
|
||||||
} else if (_state == FilteredState || _state == SearchedState) {
|
} else if (_state == FilteredState || _state == SearchedState) {
|
||||||
if (_filteredSel >= 0 && _filteredSel < _filterResults.size()) {
|
if (_filteredSel >= 0 && _filteredSel < _filterResults.size()) {
|
||||||
history = _filterResults[_filteredSel]->history;
|
history = _filterResults[_filteredSel]->history();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!history) return;
|
if (!history) return;
|
||||||
|
@ -732,9 +707,9 @@ void DialogsInner::onParentGeometryChanged() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogsInner::onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) {
|
void DialogsInner::onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) {
|
||||||
dialogs.peerNameChanged(peer, oldNames, oldChars);
|
dialogs->peerNameChanged(peer, oldNames, oldChars);
|
||||||
contactsNoDialogs.peerNameChanged(peer, oldNames, oldChars);
|
contactsNoDialogs->peerNameChanged(peer, oldNames, oldChars);
|
||||||
contacts.peerNameChanged(peer, oldNames, oldChars);
|
contacts->peerNameChanged(peer, oldNames, oldChars);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -775,35 +750,36 @@ void DialogsInner::onFilterUpdate(QString newFilter, bool force) {
|
||||||
_state = FilteredState;
|
_state = FilteredState;
|
||||||
_filterResults.clear();
|
_filterResults.clear();
|
||||||
if (!_searchInPeer && !f.isEmpty()) {
|
if (!_searchInPeer && !f.isEmpty()) {
|
||||||
DialogsList *dialogsToFilter = 0, *contactsNoDialogsToFilter = 0;
|
const Dialogs::List *toFilter = nullptr;
|
||||||
if (dialogs.list.count) {
|
if (!dialogs->isEmpty()) {
|
||||||
for (fi = fb; fi != fe; ++fi) {
|
for (fi = fb; fi != fe; ++fi) {
|
||||||
DialogsIndexed::DialogsIndex::iterator i = dialogs.index.find(fi->at(0));
|
auto found = dialogs->filtered(fi->at(0));
|
||||||
if (i == dialogs.index.cend()) {
|
if (found->isEmpty()) {
|
||||||
dialogsToFilter = 0;
|
toFilter = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!dialogsToFilter || dialogsToFilter->count > i.value()->count) {
|
if (!toFilter || toFilter->size() > found->size()) {
|
||||||
dialogsToFilter = i.value();
|
toFilter = found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (contactsNoDialogs.list.count) {
|
const Dialogs::List *toFilterContacts = nullptr;
|
||||||
|
if (!contactsNoDialogs->isEmpty()) {
|
||||||
for (fi = fb; fi != fe; ++fi) {
|
for (fi = fb; fi != fe; ++fi) {
|
||||||
DialogsIndexed::DialogsIndex::iterator i = contactsNoDialogs.index.find(fi->at(0));
|
auto found = contactsNoDialogs->filtered(fi->at(0));
|
||||||
if (i == contactsNoDialogs.index.cend()) {
|
if (found->isEmpty()) {
|
||||||
contactsNoDialogsToFilter = 0;
|
toFilterContacts = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!contactsNoDialogsToFilter || contactsNoDialogsToFilter->count > i.value()->count) {
|
if (!toFilterContacts || toFilterContacts->size() > found->size()) {
|
||||||
contactsNoDialogsToFilter = i.value();
|
toFilterContacts = found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_filterResults.reserve((dialogsToFilter ? dialogsToFilter->count : 0) + (contactsNoDialogsToFilter ? contactsNoDialogsToFilter->count : 0));
|
_filterResults.reserve((toFilter ? toFilter->size() : 0) + (toFilterContacts ? toFilterContacts->size() : 0));
|
||||||
if (dialogsToFilter && dialogsToFilter->count) {
|
if (toFilter) {
|
||||||
for (DialogRow *i = dialogsToFilter->begin, *e = dialogsToFilter->end; i != e; i = i->next) {
|
for_const (auto row, *toFilter) {
|
||||||
const PeerData::Names &names(i->history->peer->names);
|
const PeerData::Names &names(row->history()->peer->names);
|
||||||
PeerData::Names::const_iterator nb = names.cbegin(), ne = names.cend(), ni;
|
PeerData::Names::const_iterator nb = names.cbegin(), ne = names.cend(), ni;
|
||||||
for (fi = fb; fi != fe; ++fi) {
|
for (fi = fb; fi != fe; ++fi) {
|
||||||
QString filterName(*fi);
|
QString filterName(*fi);
|
||||||
|
@ -817,13 +793,13 @@ void DialogsInner::onFilterUpdate(QString newFilter, bool force) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fi == fe) {
|
if (fi == fe) {
|
||||||
_filterResults.push_back(i);
|
_filterResults.push_back(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (contactsNoDialogsToFilter && contactsNoDialogsToFilter->count) {
|
if (toFilterContacts) {
|
||||||
for (DialogRow *i = contactsNoDialogsToFilter->begin, *e = contactsNoDialogsToFilter->end; i != e; i = i->next) {
|
for_const (auto row, *toFilterContacts) {
|
||||||
const PeerData::Names &names(i->history->peer->names);
|
const PeerData::Names &names(row->history()->peer->names);
|
||||||
PeerData::Names::const_iterator nb = names.cbegin(), ne = names.cend(), ni;
|
PeerData::Names::const_iterator nb = names.cbegin(), ne = names.cend(), ni;
|
||||||
for (fi = fb; fi != fe; ++fi) {
|
for (fi = fb; fi != fe; ++fi) {
|
||||||
QString filterName(*fi);
|
QString filterName(*fi);
|
||||||
|
@ -837,7 +813,7 @@ void DialogsInner::onFilterUpdate(QString newFilter, bool force) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fi == fe) {
|
if (fi == fe) {
|
||||||
_filterResults.push_back(i);
|
_filterResults.push_back(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -916,14 +892,14 @@ PeerData *DialogsInner::updateFromParentDrag(QPoint globalPos) {
|
||||||
selByMouse = true;
|
selByMouse = true;
|
||||||
onUpdateSelected(true);
|
onUpdateSelected(true);
|
||||||
if (_state == DefaultState) {
|
if (_state == DefaultState) {
|
||||||
if (sel) return sel->history->peer;
|
if (sel) return sel->history()->peer;
|
||||||
} else if (_state == FilteredState || _state == SearchedState) {
|
} else if (_state == FilteredState || _state == SearchedState) {
|
||||||
if (_filteredSel >= 0 && _filteredSel < _filterResults.size()) {
|
if (_filteredSel >= 0 && _filteredSel < _filterResults.size()) {
|
||||||
return _filterResults[_filteredSel]->history->peer;
|
return _filterResults[_filteredSel]->history()->peer;
|
||||||
} else if (_peopleSel >= 0 && _peopleSel < _peopleResults.size()) {
|
} else if (_peopleSel >= 0 && _peopleSel < _peopleResults.size()) {
|
||||||
return _peopleResults[_peopleSel];
|
return _peopleResults[_peopleSel];
|
||||||
} else if (_searchedSel >= 0 && _searchedSel < _searchResults.size()) {
|
} else if (_searchedSel >= 0 && _searchedSel < _searchResults.size()) {
|
||||||
return _searchResults[_searchedSel]->_item->history()->peer;
|
return _searchResults[_searchedSel]->item()->history()->peer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -932,7 +908,7 @@ PeerData *DialogsInner::updateFromParentDrag(QPoint globalPos) {
|
||||||
void DialogsInner::itemRemoved(HistoryItem *item) {
|
void DialogsInner::itemRemoved(HistoryItem *item) {
|
||||||
int wasCount = _searchResults.size();
|
int wasCount = _searchResults.size();
|
||||||
for (int i = 0; i < _searchResults.size();) {
|
for (int i = 0; i < _searchResults.size();) {
|
||||||
if (_searchResults[i]->_item == item) {
|
if (_searchResults[i]->item() == item) {
|
||||||
_searchResults.remove(i);
|
_searchResults.remove(i);
|
||||||
if (item->history()->peer == _searchInMigrated) {
|
if (item->history()->peer == _searchInMigrated) {
|
||||||
if (_searchedMigratedCount > 0) --_searchedMigratedCount;
|
if (_searchedMigratedCount > 0) --_searchedMigratedCount;
|
||||||
|
@ -990,7 +966,7 @@ void DialogsInner::dialogsReceived(const QVector<MTPDialog> &added) {
|
||||||
if (!history->lastMsgDate.isNull()) {
|
if (!history->lastMsgDate.isNull()) {
|
||||||
addSavedPeersAfter(history->lastMsgDate);
|
addSavedPeersAfter(history->lastMsgDate);
|
||||||
}
|
}
|
||||||
contactsNoDialogs.del(history->peer);
|
contactsNoDialogs->del(history->peer);
|
||||||
if (history->peer->migrateFrom()) {
|
if (history->peer->migrateFrom()) {
|
||||||
removeDialog(App::historyLoaded(history->peer->migrateFrom()->id));
|
removeDialog(App::historyLoaded(history->peer->migrateFrom()->id));
|
||||||
} else if (history->peer->migrateTo() && history->peer->migrateTo()->amIn()) {
|
} else if (history->peer->migrateTo() && history->peer->migrateTo()->amIn()) {
|
||||||
|
@ -1000,9 +976,8 @@ void DialogsInner::dialogsReceived(const QVector<MTPDialog> &added) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (App::wnd()) App::wnd()->updateCounter();
|
if (App::wnd()) App::wnd()->updateCounter();
|
||||||
if (!sel && dialogs.list.count) {
|
if (!sel && !dialogs->isEmpty()) {
|
||||||
sel = dialogs.list.begin;
|
sel = *dialogs->cbegin();
|
||||||
contactSel = false;
|
|
||||||
}
|
}
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
@ -1012,7 +987,7 @@ void DialogsInner::addSavedPeersAfter(const QDateTime &date) {
|
||||||
while (!saved.isEmpty() && (date.isNull() || date < saved.lastKey())) {
|
while (!saved.isEmpty() && (date.isNull() || date < saved.lastKey())) {
|
||||||
History *history = App::history(saved.last()->id);
|
History *history = App::history(saved.last()->id);
|
||||||
history->setChatsListDate(saved.lastKey());
|
history->setChatsListDate(saved.lastKey());
|
||||||
contactsNoDialogs.del(history->peer);
|
contactsNoDialogs->del(history->peer);
|
||||||
saved.remove(saved.lastKey(), saved.last());
|
saved.remove(saved.lastKey(), saved.last());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1030,7 +1005,7 @@ bool DialogsInner::searchReceived(const QVector<MTPMessage> &messages, DialogsSe
|
||||||
HistoryItem *item = App::histories().addNewMessage(*i, NewMessageExisting);
|
HistoryItem *item = App::histories().addNewMessage(*i, NewMessageExisting);
|
||||||
int32 lastDate = dateFromMessage(*i);
|
int32 lastDate = dateFromMessage(*i);
|
||||||
if (lastDate) {
|
if (lastDate) {
|
||||||
_searchResults.push_back(new FakeDialogRow(item));
|
_searchResults.push_back(new Dialogs::FakeRow(item));
|
||||||
lastDateFound = lastDate;
|
lastDateFound = lastDate;
|
||||||
if (type == DialogsSearchFromStart || type == DialogsSearchFromOffset) {
|
if (type == DialogsSearchFromStart || type == DialogsSearchFromOffset) {
|
||||||
_lastSearchDate = lastDateFound;
|
_lastSearchDate = lastDateFound;
|
||||||
|
@ -1087,30 +1062,26 @@ void DialogsInner::contactsReceived(const QVector<MTPContact> &contacts) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!sel && contactsNoDialogs.list.count && false) {
|
|
||||||
sel = contactsNoDialogs.list.begin;
|
|
||||||
contactSel = true;
|
|
||||||
}
|
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogsInner::notify_userIsContactChanged(UserData *user, bool fromThisApp) {
|
void DialogsInner::notify_userIsContactChanged(UserData *user, bool fromThisApp) {
|
||||||
if (user->contact > 0) {
|
if (user->contact > 0) {
|
||||||
History *history = App::history(user->id);
|
History *history = App::history(user->id);
|
||||||
contacts.addByName(history);
|
contacts->addByName(history);
|
||||||
DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(user->id);
|
if (auto row = dialogs->getRow(user->id)) {
|
||||||
if (i == dialogs.list.rowByPeer.cend()) {
|
if (fromThisApp) {
|
||||||
contactsNoDialogs.addByName(history);
|
sel = row;
|
||||||
} else if (fromThisApp) {
|
}
|
||||||
sel = i.value();
|
} else {
|
||||||
contactSel = false;
|
contactsNoDialogs->addByName(history);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (sel && sel->history->peer == user) {
|
if (sel && sel->history()->peer == user) {
|
||||||
sel = 0;
|
sel = nullptr;
|
||||||
}
|
}
|
||||||
contactsNoDialogs.del(user);
|
contactsNoDialogs->del(user);
|
||||||
contacts.del(user);
|
contacts->del(user);
|
||||||
}
|
}
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
@ -1118,7 +1089,7 @@ void DialogsInner::notify_userIsContactChanged(UserData *user, bool fromThisApp)
|
||||||
void DialogsInner::refresh(bool toTop) {
|
void DialogsInner::refresh(bool toTop) {
|
||||||
int32 h = 0;
|
int32 h = 0;
|
||||||
if (_state == DefaultState) {
|
if (_state == DefaultState) {
|
||||||
h = (dialogs.list.count/* + contactsNoDialogs.list.count*/) * st::dlgHeight;
|
h = (dialogs->size()/* + contactsNoDialogs->size()*/) * st::dlgHeight;
|
||||||
if (h) {
|
if (h) {
|
||||||
if (!_addContactLnk.isHidden()) _addContactLnk.hide();
|
if (!_addContactLnk.isHidden()) _addContactLnk.hide();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1149,8 +1120,7 @@ void DialogsInner::setMouseSel(bool msel, bool toTop) {
|
||||||
selByMouse = msel;
|
selByMouse = msel;
|
||||||
if (!selByMouse && toTop) {
|
if (!selByMouse && toTop) {
|
||||||
if (_state == DefaultState) {
|
if (_state == DefaultState) {
|
||||||
sel = (dialogs.list.count ? dialogs.list.begin : (contactsNoDialogs.list.count ? contactsNoDialogs.list.begin : 0));
|
sel = !dialogs->isEmpty() ? *dialogs->cbegin() : nullptr;
|
||||||
contactSel = !dialogs.list.count && contactsNoDialogs.list.count;
|
|
||||||
} else if (_state == FilteredState || _state == SearchedState) { // don't select first elem in search
|
} else if (_state == FilteredState || _state == SearchedState) { // don't select first elem in search
|
||||||
_filteredSel = _peopleSel = _searchedSel = _hashtagSel = -1;
|
_filteredSel = _peopleSel = _searchedSel = _hashtagSel = -1;
|
||||||
setCursor(style::cur_default);
|
setCursor(style::cur_default);
|
||||||
|
@ -1213,29 +1183,23 @@ void DialogsInner::clearFilter() {
|
||||||
void DialogsInner::selectSkip(int32 direction) {
|
void DialogsInner::selectSkip(int32 direction) {
|
||||||
if (_state == DefaultState) {
|
if (_state == DefaultState) {
|
||||||
if (!sel) {
|
if (!sel) {
|
||||||
if (dialogs.list.count && direction > 0) {
|
if (!dialogs->isEmpty() && direction > 0) {
|
||||||
sel = dialogs.list.begin;
|
sel = *dialogs->cbegin();
|
||||||
} else if (false && contactsNoDialogs.list.count && direction > 0) {
|
|
||||||
sel = contactsNoDialogs.list.begin;
|
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (direction > 0) {
|
} else if (direction > 0) {
|
||||||
if (sel->next->next) {
|
auto next = dialogs->cfind(sel);
|
||||||
sel = sel->next;
|
if (++next != dialogs->cend()) {
|
||||||
} else if (false && sel->next == dialogs.list.end && contactsNoDialogs.list.count) {
|
sel = *next;
|
||||||
sel = contactsNoDialogs.list.begin;
|
|
||||||
contactSel = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (sel->prev) {
|
auto prev = dialogs->cfind(sel);
|
||||||
sel = sel->prev;
|
if (prev != dialogs->cbegin()) {
|
||||||
} else if (false && sel == contactsNoDialogs.list.begin && dialogs.list.count) {
|
sel = *(--prev);
|
||||||
sel = dialogs.list.end->prev;
|
|
||||||
contactSel = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int32 fromY = (sel->pos + (contactSel ? dialogs.list.count : 0)) * st::dlgHeight;
|
int32 fromY = sel->pos() * st::dlgHeight;
|
||||||
emit mustScrollTo(fromY, fromY + st::dlgHeight);
|
emit mustScrollTo(fromY, fromY + st::dlgHeight);
|
||||||
} else if (_state == FilteredState || _state == SearchedState) {
|
} else if (_state == FilteredState || _state == SearchedState) {
|
||||||
if (_hashtagResults.isEmpty() && _filterResults.isEmpty() && _peopleResults.isEmpty() && _searchResults.isEmpty()) return;
|
if (_hashtagResults.isEmpty() && _filterResults.isEmpty() && _peopleResults.isEmpty() && _searchResults.isEmpty()) return;
|
||||||
|
@ -1285,19 +1249,13 @@ void DialogsInner::selectSkip(int32 direction) {
|
||||||
void DialogsInner::scrollToPeer(const PeerId &peer, MsgId msgId) {
|
void DialogsInner::scrollToPeer(const PeerId &peer, MsgId msgId) {
|
||||||
int32 fromY = -1;
|
int32 fromY = -1;
|
||||||
if (_state == DefaultState) {
|
if (_state == DefaultState) {
|
||||||
DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(peer);
|
if (auto row = dialogs->getRow(peer)) {
|
||||||
if (i != dialogs.list.rowByPeer.cend()) {
|
fromY = row->pos() * st::dlgHeight;
|
||||||
fromY = i.value()->pos * st::dlgHeight;
|
|
||||||
} else if (false) {
|
|
||||||
i = contactsNoDialogs.list.rowByPeer.constFind(peer);
|
|
||||||
if (i != contactsNoDialogs.list.rowByPeer.cend()) {
|
|
||||||
fromY = (i.value()->pos + dialogs.list.count) * st::dlgHeight;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (_state == FilteredState || _state == SearchedState) {
|
} else if (_state == FilteredState || _state == SearchedState) {
|
||||||
if (msgId) {
|
if (msgId) {
|
||||||
for (int32 i = 0, c = _searchResults.size(); i < c; ++i) {
|
for (int32 i = 0, c = _searchResults.size(); i < c; ++i) {
|
||||||
if (_searchResults[i]->_item->history()->peer->id == peer && _searchResults[i]->_item->id == msgId) {
|
if (_searchResults[i]->item()->history()->peer->id == peer && _searchResults[i]->item()->id == msgId) {
|
||||||
fromY = searchedOffset() + i * st::dlgHeight;
|
fromY = searchedOffset() + i * st::dlgHeight;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1305,7 +1263,7 @@ void DialogsInner::scrollToPeer(const PeerId &peer, MsgId msgId) {
|
||||||
}
|
}
|
||||||
if (fromY < 0) {
|
if (fromY < 0) {
|
||||||
for (int32 i = 0, c = _filterResults.size(); i < c; ++i) {
|
for (int32 i = 0, c = _filterResults.size(); i < c; ++i) {
|
||||||
if (_filterResults[i]->history->peer->id == peer) {
|
if (_filterResults[i]->history()->peer->id == peer) {
|
||||||
fromY = filteredOffset() + (i * st::dlgHeight);
|
fromY = filteredOffset() + (i * st::dlgHeight);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1318,41 +1276,25 @@ void DialogsInner::scrollToPeer(const PeerId &peer, MsgId msgId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogsInner::selectSkipPage(int32 pixels, int32 direction) {
|
void DialogsInner::selectSkipPage(int32 pixels, int32 direction) {
|
||||||
int32 toSkip = pixels / int32(st::dlgHeight);
|
int toSkip = pixels / int(st::dlgHeight);
|
||||||
if (_state == DefaultState) {
|
if (_state == DefaultState) {
|
||||||
if (!sel) {
|
if (!sel) {
|
||||||
if (direction > 0 && dialogs.list.count) {
|
if (direction > 0 && !dialogs->isEmpty()) {
|
||||||
sel = dialogs.list.begin;
|
sel = *dialogs->cbegin();
|
||||||
} else if (false && direction > 0 && contactsNoDialogs.list.count) {
|
|
||||||
sel = contactsNoDialogs.list.begin;
|
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (direction > 0) {
|
if (direction > 0) {
|
||||||
while (toSkip-- && sel->next->next) {
|
for (auto i = dialogs->cfind(sel), end = dialogs->cend(); i != end && (toSkip--); ++i) {
|
||||||
sel = sel->next;
|
sel = *i;
|
||||||
}
|
|
||||||
if (false && toSkip >= 0 && sel->next == dialogs.list.end && contactsNoDialogs.list.count) {
|
|
||||||
sel = contactsNoDialogs.list.begin;
|
|
||||||
while (toSkip-- && sel->next->next) {
|
|
||||||
sel = sel->next;
|
|
||||||
}
|
|
||||||
contactSel = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (toSkip-- && sel->prev) {
|
for (auto i = dialogs->cfind(sel), b = dialogs->cbegin(); i != b && (toSkip--); --i) {
|
||||||
sel = sel->prev;
|
sel = *i;
|
||||||
}
|
|
||||||
if (toSkip >= 0 && sel == contactsNoDialogs.list.begin && dialogs.list.count) {
|
|
||||||
sel = dialogs.list.end->prev;
|
|
||||||
while (toSkip-- && sel->prev) {
|
|
||||||
sel = sel->prev;
|
|
||||||
}
|
|
||||||
contactSel = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int32 fromY = (sel->pos + (contactSel ? dialogs.list.count : 0)) * st::dlgHeight;
|
int fromY = sel->pos() * st::dlgHeight;
|
||||||
emit mustScrollTo(fromY, fromY + st::dlgHeight);
|
emit mustScrollTo(fromY, fromY + st::dlgHeight);
|
||||||
} else {
|
} else {
|
||||||
return selectSkip(direction * toSkip);
|
return selectSkip(direction * toSkip);
|
||||||
|
@ -1366,23 +1308,19 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) {
|
||||||
int32 yTo = yFrom + parentWidget()->height() * 5;
|
int32 yTo = yFrom + parentWidget()->height() * 5;
|
||||||
MTP::clearLoaderPriorities();
|
MTP::clearLoaderPriorities();
|
||||||
if (_state == DefaultState) {
|
if (_state == DefaultState) {
|
||||||
int32 otherStart = dialogs.list.count * st::dlgHeight;
|
int32 otherStart = dialogs->size() * st::dlgHeight;
|
||||||
if (yFrom < otherStart) {
|
if (yFrom < otherStart) {
|
||||||
dialogs.list.adjustCurrent(yFrom, st::dlgHeight);
|
for (auto i = dialogs->cfind(yFrom, st::dlgHeight), end = dialogs->cend(); i != end; ++i) {
|
||||||
for (DialogRow *row = dialogs.list.current; row != dialogs.list.end && (row->pos * st::dlgHeight) < yTo; row = row->next) {
|
if (((*i)->pos() * st::dlgHeight) >= yTo) {
|
||||||
row->history->peer->loadUserpic();
|
break;
|
||||||
|
}
|
||||||
|
(*i)->history()->peer->loadUserpic();
|
||||||
}
|
}
|
||||||
yFrom = 0;
|
yFrom = 0;
|
||||||
} else {
|
} else {
|
||||||
yFrom -= otherStart;
|
yFrom -= otherStart;
|
||||||
}
|
}
|
||||||
yTo -= otherStart;
|
yTo -= otherStart;
|
||||||
if (yTo > 0) {
|
|
||||||
contactsNoDialogs.list.adjustCurrent(yFrom, st::dlgHeight);
|
|
||||||
for (DialogRow *row = contactsNoDialogs.list.current; row != contactsNoDialogs.list.end && (row->pos * st::dlgHeight) < yTo; row = row->next) {
|
|
||||||
row->history->peer->loadUserpic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (_state == FilteredState || _state == SearchedState) {
|
} else if (_state == FilteredState || _state == SearchedState) {
|
||||||
int32 from = (yFrom - filteredOffset()) / st::dlgHeight;
|
int32 from = (yFrom - filteredOffset()) / st::dlgHeight;
|
||||||
if (from < 0) from = 0;
|
if (from < 0) from = 0;
|
||||||
|
@ -1391,7 +1329,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) {
|
||||||
if (to > _filterResults.size()) to = _filterResults.size();
|
if (to > _filterResults.size()) to = _filterResults.size();
|
||||||
|
|
||||||
for (; from < to; ++from) {
|
for (; from < to; ++from) {
|
||||||
_filterResults[from]->history->peer->loadUserpic();
|
_filterResults[from]->history()->peer->loadUserpic();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1412,7 +1350,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) {
|
||||||
if (to > _searchResults.size()) to = _searchResults.size();
|
if (to > _searchResults.size()) to = _searchResults.size();
|
||||||
|
|
||||||
for (; from < to; ++from) {
|
for (; from < to; ++from) {
|
||||||
_searchResults[from]->_item->history()->peer->loadUserpic();
|
_searchResults[from]->item()->history()->peer->loadUserpic();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1422,7 +1360,7 @@ bool DialogsInner::choosePeer() {
|
||||||
History *history = 0;
|
History *history = 0;
|
||||||
MsgId msgId = ShowAtUnreadMsgId;
|
MsgId msgId = ShowAtUnreadMsgId;
|
||||||
if (_state == DefaultState) {
|
if (_state == DefaultState) {
|
||||||
if (sel) history = sel->history;
|
if (sel) history = sel->history();
|
||||||
} else if (_state == FilteredState || _state == SearchedState) {
|
} else if (_state == FilteredState || _state == SearchedState) {
|
||||||
if (_hashtagSel >= 0 && _hashtagSel < _hashtagResults.size()) {
|
if (_hashtagSel >= 0 && _hashtagSel < _hashtagResults.size()) {
|
||||||
QString hashtag = _hashtagResults.at(_hashtagSel);
|
QString hashtag = _hashtagResults.at(_hashtagSel);
|
||||||
|
@ -1450,12 +1388,12 @@ bool DialogsInner::choosePeer() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (_filteredSel >= 0 && _filteredSel < _filterResults.size()) {
|
if (_filteredSel >= 0 && _filteredSel < _filterResults.size()) {
|
||||||
history = _filterResults[_filteredSel]->history;
|
history = _filterResults[_filteredSel]->history();
|
||||||
} else if (_peopleSel >= 0 && _peopleSel < _peopleResults.size()) {
|
} else if (_peopleSel >= 0 && _peopleSel < _peopleResults.size()) {
|
||||||
history = App::history(_peopleResults[_peopleSel]->id);
|
history = App::history(_peopleResults[_peopleSel]->id);
|
||||||
} else if (_searchedSel >= 0 && _searchedSel < _searchResults.size()) {
|
} else if (_searchedSel >= 0 && _searchedSel < _searchResults.size()) {
|
||||||
history = _searchResults[_searchedSel]->_item->history();
|
history = _searchResults[_searchedSel]->item()->history();
|
||||||
msgId = _searchResults[_searchedSel]->_item->id;
|
msgId = _searchResults[_searchedSel]->item()->id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (history) {
|
if (history) {
|
||||||
|
@ -1504,8 +1442,7 @@ void DialogsInner::saveRecentHashtags(const QString &text) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogsInner::destroyData() {
|
void DialogsInner::destroyData() {
|
||||||
sel = 0;
|
sel = nullptr;
|
||||||
contactSel = false;
|
|
||||||
_hashtagSel = -1;
|
_hashtagSel = -1;
|
||||||
_hashtagResults.clear();
|
_hashtagResults.clear();
|
||||||
_filteredSel = -1;
|
_filteredSel = -1;
|
||||||
|
@ -1520,54 +1457,39 @@ void DialogsInner::destroyData() {
|
||||||
|
|
||||||
void DialogsInner::peerBefore(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) const {
|
void DialogsInner::peerBefore(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) const {
|
||||||
if (!inPeer) {
|
if (!inPeer) {
|
||||||
outPeer = 0;
|
outPeer = nullptr;
|
||||||
outMsg = 0;
|
outMsg = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_state == DefaultState) {
|
if (_state == DefaultState) {
|
||||||
DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(inPeer->id);
|
if (auto row = dialogs->getRow(inPeer->id)) {
|
||||||
if (i == dialogs.list.rowByPeer.constEnd()) {
|
auto i = dialogs->cfind(row);
|
||||||
i = contactsNoDialogs.list.rowByPeer.constFind(inPeer->id);
|
if (i != dialogs->cbegin()) {
|
||||||
if (i == contactsNoDialogs.list.rowByPeer.cend()) {
|
outPeer = (*(--i))->history()->peer;
|
||||||
outPeer = 0;
|
|
||||||
outMsg = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (i.value()->prev) {
|
|
||||||
outPeer = i.value()->prev->history->peer;
|
|
||||||
outMsg = ShowAtUnreadMsgId;
|
|
||||||
return;
|
|
||||||
} else if (dialogs.list.count) {
|
|
||||||
outPeer = dialogs.list.end->prev->history->peer;
|
|
||||||
outMsg = ShowAtUnreadMsgId;
|
outMsg = ShowAtUnreadMsgId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
outPeer = 0;
|
|
||||||
outMsg = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (i.value()->prev) {
|
|
||||||
outPeer = i.value()->prev->history->peer;
|
|
||||||
outMsg = ShowAtUnreadMsgId;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
outPeer = nullptr;
|
||||||
|
outMsg = 0;
|
||||||
|
return;
|
||||||
} else if (_state == FilteredState || _state == SearchedState) {
|
} else if (_state == FilteredState || _state == SearchedState) {
|
||||||
if (inMsg && !_searchResults.isEmpty()) {
|
if (inMsg && !_searchResults.isEmpty()) {
|
||||||
for (SearchResults::const_iterator b = _searchResults.cbegin(), i = b + 1, e = _searchResults.cend(); i != e; ++i) {
|
for (SearchResults::const_iterator b = _searchResults.cbegin(), i = b + 1, e = _searchResults.cend(); i != e; ++i) {
|
||||||
if ((*i)->_item->history()->peer == inPeer && (*i)->_item->id == inMsg) {
|
if ((*i)->item()->history()->peer == inPeer && (*i)->item()->id == inMsg) {
|
||||||
SearchResults::const_iterator j = i - 1;
|
SearchResults::const_iterator j = i - 1;
|
||||||
outPeer = (*j)->_item->history()->peer;
|
outPeer = (*j)->item()->history()->peer;
|
||||||
outMsg = (*j)->_item->id;
|
outMsg = (*j)->item()->id;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_searchResults.at(0)->_item->history()->peer == inPeer && _searchResults.at(0)->_item->id == inMsg) {
|
if (_searchResults.at(0)->item()->history()->peer == inPeer && _searchResults.at(0)->item()->id == inMsg) {
|
||||||
outMsg = ShowAtUnreadMsgId;
|
outMsg = ShowAtUnreadMsgId;
|
||||||
if (_peopleResults.isEmpty()) {
|
if (_peopleResults.isEmpty()) {
|
||||||
if (_filterResults.isEmpty()) {
|
if (_filterResults.isEmpty()) {
|
||||||
outPeer = 0;
|
outPeer = nullptr;
|
||||||
} else {
|
} else {
|
||||||
outPeer = _filterResults.back()->history->peer;
|
outPeer = _filterResults.back()->history()->peer;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
outPeer = _peopleResults.back();
|
outPeer = _peopleResults.back();
|
||||||
|
@ -1576,7 +1498,7 @@ void DialogsInner::peerBefore(const PeerData *inPeer, MsgId inMsg, PeerData *&ou
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!_peopleResults.isEmpty() && _peopleResults.at(0) == inPeer) {
|
if (!_peopleResults.isEmpty() && _peopleResults.at(0) == inPeer) {
|
||||||
outPeer = _filterResults.isEmpty() ? 0 : _filterResults.back()->history->peer;
|
outPeer = _filterResults.isEmpty() ? 0 : _filterResults.back()->history()->peer;
|
||||||
outMsg = ShowAtUnreadMsgId;
|
outMsg = ShowAtUnreadMsgId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1589,65 +1511,49 @@ void DialogsInner::peerBefore(const PeerData *inPeer, MsgId inMsg, PeerData *&ou
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_filterResults.isEmpty() || _filterResults.at(0)->history->peer == inPeer) {
|
if (_filterResults.isEmpty() || _filterResults.at(0)->history()->peer == inPeer) {
|
||||||
outPeer = 0;
|
outPeer = nullptr;
|
||||||
outMsg = 0;
|
outMsg = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (FilteredDialogs::const_iterator b = _filterResults.cbegin(), i = b + 1, e = _filterResults.cend(); i != e; ++i) {
|
for (FilteredDialogs::const_iterator b = _filterResults.cbegin(), i = b + 1, e = _filterResults.cend(); i != e; ++i) {
|
||||||
if ((*i)->history->peer == inPeer) {
|
if ((*i)->history()->peer == inPeer) {
|
||||||
outPeer = (*(i - 1))->history->peer;
|
outPeer = (*(i - 1))->history()->peer;
|
||||||
outMsg = ShowAtUnreadMsgId;
|
outMsg = ShowAtUnreadMsgId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outPeer = 0;
|
outPeer = nullptr;
|
||||||
outMsg = 0;
|
outMsg = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogsInner::peerAfter(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) const {
|
void DialogsInner::peerAfter(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) const {
|
||||||
if (!inPeer) {
|
if (!inPeer) {
|
||||||
outPeer = 0;
|
outPeer = nullptr;
|
||||||
outMsg = 0;
|
outMsg = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_state == DefaultState) {
|
if (_state == DefaultState) {
|
||||||
DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(inPeer->id);
|
if (auto row = dialogs->getRow(inPeer->id)) {
|
||||||
if (i == dialogs.list.rowByPeer.constEnd()) {
|
auto i = dialogs->cfind(row) + 1;
|
||||||
//i = contactsNoDialogs.list.rowByPeer.constFind(inPeer->id);
|
if (i != dialogs->cend()) {
|
||||||
//if (i == contactsNoDialogs.list.rowByPeer.cend()) {
|
outPeer = (*i)->history()->peer;
|
||||||
// outPeer = 0;
|
outMsg = ShowAtUnreadMsgId;
|
||||||
// outMsg = 0;
|
return;
|
||||||
// return;
|
}
|
||||||
//}
|
|
||||||
//if (i.value()->next != contactsNoDialogs.list.end) {
|
|
||||||
// outPeer = i.value()->next->history->peer;
|
|
||||||
// outMsg = ShowAtUnreadMsgId;
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
outPeer = 0;
|
|
||||||
outMsg = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i.value()->next != dialogs.list.end) {
|
|
||||||
outPeer = i.value()->next->history->peer;
|
|
||||||
outMsg = ShowAtUnreadMsgId;
|
|
||||||
return;
|
|
||||||
} else if (false && contactsNoDialogs.list.count) {
|
|
||||||
outPeer = contactsNoDialogs.list.begin->history->peer;
|
|
||||||
outMsg = ShowAtUnreadMsgId;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
outPeer = nullptr;
|
||||||
|
outMsg = 0;
|
||||||
|
return;
|
||||||
} else if (_state == FilteredState || _state == SearchedState) {
|
} else if (_state == FilteredState || _state == SearchedState) {
|
||||||
if (inMsg) {
|
if (inMsg) {
|
||||||
for (SearchResults::const_iterator i = _searchResults.cbegin(), e = _searchResults.cend(); i != e; ++i) {
|
for (SearchResults::const_iterator i = _searchResults.cbegin(), e = _searchResults.cend(); i != e; ++i) {
|
||||||
if ((*i)->_item->history()->peer == inPeer && (*i)->_item->id == inMsg) {
|
if ((*i)->item()->history()->peer == inPeer && (*i)->item()->id == inMsg) {
|
||||||
++i;
|
++i;
|
||||||
outPeer = (i == e) ? 0 : (*i)->_item->history()->peer;
|
outPeer = (i == e) ? nullptr : (*i)->item()->history()->peer;
|
||||||
outMsg = (i == e) ? 0 : (*i)->_item->id;
|
outMsg = (i == e) ? 0 : (*i)->item()->id;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1656,42 +1562,42 @@ void DialogsInner::peerAfter(const PeerData *inPeer, MsgId inMsg, PeerData *&out
|
||||||
if ((*i) == inPeer) {
|
if ((*i) == inPeer) {
|
||||||
++i;
|
++i;
|
||||||
if (i == e && !_searchResults.isEmpty()) {
|
if (i == e && !_searchResults.isEmpty()) {
|
||||||
outPeer = _searchResults.front()->_item->history()->peer;
|
outPeer = _searchResults.front()->item()->history()->peer;
|
||||||
outMsg = _searchResults.front()->_item->id;
|
outMsg = _searchResults.front()->item()->id;
|
||||||
} else {
|
} else {
|
||||||
outPeer = (i == e) ? 0 : (*i);
|
outPeer = (i == e) ? nullptr : (*i);
|
||||||
outMsg = ShowAtUnreadMsgId;
|
outMsg = ShowAtUnreadMsgId;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (FilteredDialogs::const_iterator i = _filterResults.cbegin(), e = _filterResults.cend(); i != e; ++i) {
|
for (FilteredDialogs::const_iterator i = _filterResults.cbegin(), e = _filterResults.cend(); i != e; ++i) {
|
||||||
if ((*i)->history->peer == inPeer) {
|
if ((*i)->history()->peer == inPeer) {
|
||||||
++i;
|
++i;
|
||||||
if (i == e && !_peopleResults.isEmpty()) {
|
if (i == e && !_peopleResults.isEmpty()) {
|
||||||
outPeer = _peopleResults.front();
|
outPeer = _peopleResults.front();
|
||||||
outMsg = ShowAtUnreadMsgId;
|
outMsg = ShowAtUnreadMsgId;
|
||||||
} else if (i == e && !_searchResults.isEmpty()) {
|
} else if (i == e && !_searchResults.isEmpty()) {
|
||||||
outPeer = _searchResults.front()->_item->history()->peer;
|
outPeer = _searchResults.front()->item()->history()->peer;
|
||||||
outMsg = _searchResults.front()->_item->id;
|
outMsg = _searchResults.front()->item()->id;
|
||||||
} else {
|
} else {
|
||||||
outPeer = (i == e) ? 0 : (*i)->history->peer;
|
outPeer = (i == e) ? nullptr : (*i)->history()->peer;
|
||||||
outMsg = ShowAtUnreadMsgId;
|
outMsg = ShowAtUnreadMsgId;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outPeer = 0;
|
outPeer = nullptr;
|
||||||
outMsg = 0;
|
outMsg = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DialogsIndexed &DialogsInner::contactsList() {
|
Dialogs::IndexedList *DialogsInner::contactsList() {
|
||||||
return contacts;
|
return contacts.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
DialogsIndexed &DialogsInner::dialogsList() {
|
Dialogs::IndexedList *DialogsInner::dialogsList() {
|
||||||
return dialogs;
|
return dialogs.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
DialogsInner::FilteredDialogs &DialogsInner::filteredList() {
|
DialogsInner::FilteredDialogs &DialogsInner::filteredList() {
|
||||||
|
@ -1802,7 +1708,7 @@ void DialogsWidget::createDialog(History *history) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogsWidget::dlgUpdated(DialogRow *row) {
|
void DialogsWidget::dlgUpdated(Dialogs::Row *row) {
|
||||||
_inner.dlgUpdated(row);
|
_inner.dlgUpdated(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2365,7 +2271,7 @@ void DialogsWidget::onListScroll() {
|
||||||
if (_scroll.scrollTop() > (_inner.searchList().size() + _inner.filteredList().size() + _inner.peopleList().size()) * st::dlgHeight - PreloadHeightsCount * _scroll.height()) {
|
if (_scroll.scrollTop() > (_inner.searchList().size() + _inner.filteredList().size() + _inner.peopleList().size()) * st::dlgHeight - PreloadHeightsCount * _scroll.height()) {
|
||||||
onSearchMore();
|
onSearchMore();
|
||||||
}
|
}
|
||||||
} else if (_scroll.scrollTop() > _inner.dialogsList().list.count * st::dlgHeight - PreloadHeightsCount * _scroll.height()) {
|
} else if (_scroll.scrollTop() > _inner.dialogsList()->size() * st::dlgHeight - PreloadHeightsCount * _scroll.height()) {
|
||||||
loadDialogs();
|
loadDialogs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2541,11 +2447,11 @@ void DialogsWidget::removeDialog(History *history) {
|
||||||
onFilterUpdate();
|
onFilterUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
DialogsIndexed &DialogsWidget::contactsList() {
|
Dialogs::IndexedList *DialogsWidget::contactsList() {
|
||||||
return _inner.contactsList();
|
return _inner.contactsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
DialogsIndexed &DialogsWidget::dialogsList() {
|
Dialogs::IndexedList *DialogsWidget::dialogsList() {
|
||||||
return _inner.dialogsList();
|
return _inner.dialogsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
class MainWidget;
|
class MainWidget;
|
||||||
|
namespace Dialogs {
|
||||||
|
class Row;
|
||||||
|
class FakeRow;
|
||||||
|
class IndexedList;
|
||||||
|
} // namespace Dialogs
|
||||||
|
|
||||||
enum DialogsSearchRequestType {
|
enum DialogsSearchRequestType {
|
||||||
DialogsSearchFromStart,
|
DialogsSearchFromStart,
|
||||||
|
@ -67,7 +72,7 @@ public:
|
||||||
void selectSkipPage(int32 pixels, int32 direction);
|
void selectSkipPage(int32 pixels, int32 direction);
|
||||||
|
|
||||||
void createDialog(History *history);
|
void createDialog(History *history);
|
||||||
void dlgUpdated(DialogRow *row);
|
void dlgUpdated(Dialogs::Row *row);
|
||||||
void dlgUpdated(History *row, MsgId msgId);
|
void dlgUpdated(History *row, MsgId msgId);
|
||||||
void removeDialog(History *history);
|
void removeDialog(History *history);
|
||||||
|
|
||||||
|
@ -84,12 +89,12 @@ public:
|
||||||
void peerAfter(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) const;
|
void peerAfter(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) const;
|
||||||
void scrollToPeer(const PeerId &peer, MsgId msgId);
|
void scrollToPeer(const PeerId &peer, MsgId msgId);
|
||||||
|
|
||||||
typedef QVector<DialogRow*> FilteredDialogs;
|
typedef QVector<Dialogs::Row*> FilteredDialogs;
|
||||||
typedef QVector<PeerData*> PeopleResults;
|
typedef QVector<PeerData*> PeopleResults;
|
||||||
typedef QVector<FakeDialogRow*> SearchResults;
|
typedef QVector<Dialogs::FakeRow*> SearchResults;
|
||||||
|
|
||||||
DialogsIndexed &contactsList();
|
Dialogs::IndexedList *contactsList();
|
||||||
DialogsIndexed &dialogsList();
|
Dialogs::IndexedList *dialogsList();
|
||||||
FilteredDialogs &filteredList();
|
FilteredDialogs &filteredList();
|
||||||
PeopleResults &peopleList();
|
PeopleResults &peopleList();
|
||||||
SearchResults &searchList();
|
SearchResults &searchList();
|
||||||
|
@ -129,7 +134,7 @@ public slots:
|
||||||
void onParentGeometryChanged();
|
void onParentGeometryChanged();
|
||||||
void onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
|
void onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
|
||||||
void onPeerPhotoChanged(PeerData *peer);
|
void onPeerPhotoChanged(PeerData *peer);
|
||||||
void onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow);
|
void onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow);
|
||||||
|
|
||||||
void onContextProfile();
|
void onContextProfile();
|
||||||
void onContextToggleNotifications();
|
void onContextToggleNotifications();
|
||||||
|
@ -165,46 +170,52 @@ private:
|
||||||
bool menuPeerMuted();
|
bool menuPeerMuted();
|
||||||
void contextBlockDone(QPair<UserData*, bool> data, const MTPBool &result);
|
void contextBlockDone(QPair<UserData*, bool> data, const MTPBool &result);
|
||||||
|
|
||||||
DialogsIndexed dialogs;
|
using DialogsList = UniquePointer<Dialogs::IndexedList>;
|
||||||
DialogsIndexed contactsNoDialogs;
|
DialogsList dialogs;
|
||||||
DialogsIndexed contacts;
|
DialogsList contactsNoDialogs;
|
||||||
DialogRow *sel;
|
DialogsList contacts;
|
||||||
bool contactSel;
|
Dialogs::Row *sel = nullptr;
|
||||||
bool selByMouse;
|
bool selByMouse = false;
|
||||||
|
|
||||||
QString _filter, _hashtagFilter;
|
QString _filter, _hashtagFilter;
|
||||||
|
|
||||||
QStringList _hashtagResults;
|
QStringList _hashtagResults;
|
||||||
int32 _hashtagSel;
|
int _hashtagSel = -1;
|
||||||
|
|
||||||
FilteredDialogs _filterResults;
|
FilteredDialogs _filterResults;
|
||||||
int32 _filteredSel;
|
int _filteredSel = -1;
|
||||||
|
|
||||||
SearchResults _searchResults;
|
SearchResults _searchResults;
|
||||||
int32 _searchedCount, _searchedMigratedCount, _searchedSel;
|
int _searchedCount = 0;
|
||||||
|
int _searchedMigratedCount = 0;
|
||||||
|
int _searchedSel = -1;
|
||||||
|
|
||||||
QString _peopleQuery;
|
QString _peopleQuery;
|
||||||
PeopleResults _peopleResults;
|
PeopleResults _peopleResults;
|
||||||
int32 _peopleSel;
|
int _peopleSel = -1;
|
||||||
|
|
||||||
int32 _lastSearchDate;
|
int _lastSearchDate = 0;
|
||||||
PeerData *_lastSearchPeer;
|
PeerData *_lastSearchPeer = nullptr;
|
||||||
MsgId _lastSearchId, _lastSearchMigratedId;
|
MsgId _lastSearchId = 0;
|
||||||
|
MsgId _lastSearchMigratedId = 0;
|
||||||
|
|
||||||
State _state;
|
State _state = DefaultState;
|
||||||
|
|
||||||
QPoint lastMousePos;
|
QPoint lastMousePos;
|
||||||
|
|
||||||
void paintDialog(QPainter &p, DialogRow *dialog);
|
void paintDialog(QPainter &p, Dialogs::Row *dialog);
|
||||||
|
|
||||||
LinkButton _addContactLnk;
|
LinkButton _addContactLnk;
|
||||||
IconedButton _cancelSearchInPeer;
|
IconedButton _cancelSearchInPeer;
|
||||||
|
|
||||||
bool _overDelete;
|
bool _overDelete = false;
|
||||||
|
|
||||||
PeerData *_searchInPeer, *_searchInMigrated, *_menuPeer, *_menuActionPeer;
|
PeerData *_searchInPeer = nullptr;
|
||||||
|
PeerData *_searchInMigrated = nullptr;
|
||||||
|
PeerData *_menuPeer = nullptr;
|
||||||
|
PeerData *_menuActionPeer = nullptr;
|
||||||
|
|
||||||
PopupMenu *_menu;
|
PopupMenu *_menu = nullptr;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -233,7 +244,7 @@ public:
|
||||||
|
|
||||||
void loadDialogs();
|
void loadDialogs();
|
||||||
void createDialog(History *history);
|
void createDialog(History *history);
|
||||||
void dlgUpdated(DialogRow *row);
|
void dlgUpdated(Dialogs::Row *row);
|
||||||
void dlgUpdated(History *row, MsgId msgId);
|
void dlgUpdated(History *row, MsgId msgId);
|
||||||
|
|
||||||
void dialogsToUp();
|
void dialogsToUp();
|
||||||
|
@ -249,8 +260,8 @@ public:
|
||||||
|
|
||||||
void removeDialog(History *history);
|
void removeDialog(History *history);
|
||||||
|
|
||||||
DialogsIndexed &contactsList();
|
Dialogs::IndexedList *contactsList();
|
||||||
DialogsIndexed &dialogsList();
|
Dialogs::IndexedList *dialogsList();
|
||||||
|
|
||||||
void searchMessages(const QString &query, PeerData *inPeer = 0);
|
void searchMessages(const QString &query, PeerData *inPeer = 0);
|
||||||
void onSearchMore();
|
void onSearchMore();
|
||||||
|
|
|
@ -19,18 +19,18 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
#include "history.h"
|
||||||
|
|
||||||
|
#include "dialogs/dialogs_indexed_list.h"
|
||||||
#include "ui/style.h"
|
#include "ui/style.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
|
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "fileuploader.h"
|
#include "fileuploader.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "ui/filedialog.h"
|
#include "ui/filedialog.h"
|
||||||
|
|
||||||
#include "boxes/addcontactbox.h"
|
#include "boxes/addcontactbox.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
|
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
|
|
||||||
|
@ -87,177 +87,6 @@ void historyInit() {
|
||||||
_initTextOptions();
|
_initTextOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogRow::paint(Painter &p, int32 w, bool act, bool sel, bool onlyBackground) const {
|
|
||||||
QRect fullRect(0, 0, w, st::dlgHeight);
|
|
||||||
p.fillRect(fullRect, (act ? st::dlgActiveBG : (sel ? st::dlgHoverBG : st::dlgBG))->b);
|
|
||||||
if (onlyBackground) return;
|
|
||||||
|
|
||||||
PeerData *userpicPeer = (history->peer->migrateTo() ? history->peer->migrateTo() : history->peer);
|
|
||||||
userpicPeer->paintUserpicLeft(p, st::dlgPhotoSize, st::dlgPaddingHor, st::dlgPaddingVer, w);
|
|
||||||
|
|
||||||
int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding;
|
|
||||||
int32 namewidth = w - nameleft - st::dlgPaddingHor;
|
|
||||||
QRect rectForName(nameleft, st::dlgPaddingVer + st::dlgNameTop, namewidth, st::msgNameFont->height);
|
|
||||||
|
|
||||||
// draw chat icon
|
|
||||||
if (history->peer->isChat() || history->peer->isMegagroup()) {
|
|
||||||
p.drawPixmap(QPoint(rectForName.left() + st::dlgChatImgPos.x(), rectForName.top() + st::dlgChatImgPos.y()), App::sprite(), (act ? st::dlgActiveChatImg : st::dlgChatImg));
|
|
||||||
rectForName.setLeft(rectForName.left() + st::dlgImgSkip);
|
|
||||||
} else if (history->peer->isChannel()) {
|
|
||||||
p.drawPixmap(QPoint(rectForName.left() + st::dlgChannelImgPos.x(), rectForName.top() + st::dlgChannelImgPos.y()), App::sprite(), (act ? st::dlgActiveChannelImg : st::dlgChannelImg));
|
|
||||||
rectForName.setLeft(rectForName.left() + st::dlgImgSkip);
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryItem *last = history->lastMsg;
|
|
||||||
if (!last) {
|
|
||||||
p.setFont(st::dlgHistFont->f);
|
|
||||||
p.setPen((act ? st::dlgActiveColor : st::dlgSystemColor)->p);
|
|
||||||
if (history->typing.isEmpty() && history->sendActions.isEmpty()) {
|
|
||||||
p.drawText(nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgFont->ascent + st::dlgSep, lang(lng_empty_history));
|
|
||||||
} else {
|
|
||||||
history->typingText.drawElided(p, nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, namewidth);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// draw date
|
|
||||||
QDateTime now(QDateTime::currentDateTime()), lastTime(last->date);
|
|
||||||
QDate nowDate(now.date()), lastDate(lastTime.date());
|
|
||||||
QString dt;
|
|
||||||
if (lastDate == nowDate) {
|
|
||||||
dt = lastTime.toString(cTimeFormat());
|
|
||||||
} else if (lastDate.year() == nowDate.year() && lastDate.weekNumber() == nowDate.weekNumber()) {
|
|
||||||
dt = langDayOfWeek(lastDate);
|
|
||||||
} else {
|
|
||||||
dt = lastDate.toString(qsl("d.MM.yy"));
|
|
||||||
}
|
|
||||||
int32 dtWidth = st::dlgDateFont->width(dt);
|
|
||||||
rectForName.setWidth(rectForName.width() - dtWidth - st::dlgDateSkip);
|
|
||||||
p.setFont(st::dlgDateFont->f);
|
|
||||||
p.setPen((act ? st::dlgActiveDateColor : st::dlgDateColor)->p);
|
|
||||||
p.drawText(rectForName.left() + rectForName.width() + st::dlgDateSkip, rectForName.top() + st::msgNameFont->height - st::msgDateFont->descent, dt);
|
|
||||||
|
|
||||||
// draw check
|
|
||||||
if (last->needCheck()) {
|
|
||||||
const style::sprite *check;
|
|
||||||
if (last->id > 0) {
|
|
||||||
if (last->unread()) {
|
|
||||||
check = act ? &st::dlgActiveCheckImg : &st::dlgCheckImg;
|
|
||||||
} else {
|
|
||||||
check = act ? &st::dlgActiveDblCheckImg: &st::dlgDblCheckImg;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
check = act ? &st::dlgActiveSendImg : &st::dlgSendImg;
|
|
||||||
}
|
|
||||||
rectForName.setWidth(rectForName.width() - check->pxWidth() - st::dlgCheckSkip);
|
|
||||||
p.drawPixmap(QPoint(rectForName.left() + rectForName.width() + st::dlgCheckLeft, rectForName.top() + st::dlgCheckTop), App::sprite(), *check);
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw unread
|
|
||||||
int32 lastWidth = namewidth, unread = history->unreadCount;
|
|
||||||
if (history->peer->migrateFrom()) {
|
|
||||||
if (History *h = App::historyLoaded(history->peer->migrateFrom()->id)) {
|
|
||||||
unread += h->unreadCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (unread) {
|
|
||||||
QString unreadStr = QString::number(unread);
|
|
||||||
int32 unreadWidth = st::dlgUnreadFont->width(unreadStr);
|
|
||||||
int32 unreadRectWidth = unreadWidth + 2 * st::dlgUnreadPaddingHor;
|
|
||||||
int32 unreadRectHeight = st::dlgUnreadFont->height + 2 * st::dlgUnreadPaddingVer;
|
|
||||||
int32 unreadRectLeft = w - st::dlgPaddingHor - unreadRectWidth;
|
|
||||||
int32 unreadRectTop = st::dlgHeight - st::dlgPaddingVer - unreadRectHeight;
|
|
||||||
lastWidth -= unreadRectWidth + st::dlgUnreadPaddingHor;
|
|
||||||
p.setBrush((act ? (history->mute ? st::dlgActiveUnreadMutedBG : st::dlgActiveUnreadBG) : (history->mute ? st::dlgUnreadMutedBG : st::dlgUnreadBG))->b);
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
p.drawRoundedRect(unreadRectLeft, unreadRectTop, unreadRectWidth, unreadRectHeight, st::dlgUnreadRadius, st::dlgUnreadRadius);
|
|
||||||
p.setFont(st::dlgUnreadFont->f);
|
|
||||||
p.setPen((act ? st::dlgActiveUnreadColor : st::dlgUnreadColor)->p);
|
|
||||||
p.drawText(unreadRectLeft + st::dlgUnreadPaddingHor, unreadRectTop + st::dlgUnreadPaddingVer + st::dlgUnreadFont->ascent, unreadStr);
|
|
||||||
}
|
|
||||||
if (history->typing.isEmpty() && history->sendActions.isEmpty()) {
|
|
||||||
last->drawInDialog(p, QRect(nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, lastWidth, st::dlgFont->height), act, history->textCachedFor, history->lastItemTextCache);
|
|
||||||
} else {
|
|
||||||
p.setPen((act ? st::dlgActiveColor : st::dlgSystemColor)->p);
|
|
||||||
history->typingText.drawElided(p, nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, lastWidth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (history->peer->isUser() && history->peer->isVerified()) {
|
|
||||||
rectForName.setWidth(rectForName.width() - st::verifiedCheck.pxWidth() - st::verifiedCheckPos.x());
|
|
||||||
p.drawSprite(rectForName.topLeft() + QPoint(qMin(history->peer->dialogName().maxWidth(), rectForName.width()), 0) + st::verifiedCheckPos, (act ? st::verifiedCheckInv : st::verifiedCheck));
|
|
||||||
}
|
|
||||||
|
|
||||||
p.setPen((act ? st::dlgActiveColor : st::dlgNameColor)->p);
|
|
||||||
history->peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
|
|
||||||
}
|
|
||||||
|
|
||||||
void FakeDialogRow::paint(Painter &p, int32 w, bool act, bool sel, bool onlyBackground) const {
|
|
||||||
QRect fullRect(0, 0, w, st::dlgHeight);
|
|
||||||
p.fillRect(fullRect, (act ? st::dlgActiveBG : (sel ? st::dlgHoverBG : st::dlgBG))->b);
|
|
||||||
if (onlyBackground) return;
|
|
||||||
|
|
||||||
History *history = _item->history();
|
|
||||||
PeerData *userpicPeer = (history->peer->migrateTo() ? history->peer->migrateTo() : history->peer);
|
|
||||||
userpicPeer->paintUserpicLeft(p, st::dlgPhotoSize, st::dlgPaddingHor, st::dlgPaddingVer, w);
|
|
||||||
|
|
||||||
int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding;
|
|
||||||
int32 namewidth = w - nameleft - st::dlgPaddingHor;
|
|
||||||
QRect rectForName(nameleft, st::dlgPaddingVer + st::dlgNameTop, namewidth, st::msgNameFont->height);
|
|
||||||
|
|
||||||
// draw chat icon
|
|
||||||
if (history->peer->isChat() || history->peer->isMegagroup()) {
|
|
||||||
p.drawPixmap(QPoint(rectForName.left() + st::dlgChatImgPos.x(), rectForName.top() + st::dlgChatImgPos.y()), App::sprite(), (act ? st::dlgActiveChatImg : st::dlgChatImg));
|
|
||||||
rectForName.setLeft(rectForName.left() + st::dlgImgSkip);
|
|
||||||
} else if (history->peer->isChannel()) {
|
|
||||||
p.drawPixmap(QPoint(rectForName.left() + st::dlgChannelImgPos.x(), rectForName.top() + st::dlgChannelImgPos.y()), App::sprite(), (act ? st::dlgActiveChannelImg : st::dlgChannelImg));
|
|
||||||
rectForName.setLeft(rectForName.left() + st::dlgImgSkip);
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw date
|
|
||||||
QDateTime now(QDateTime::currentDateTime()), lastTime(_item->date);
|
|
||||||
QDate nowDate(now.date()), lastDate(lastTime.date());
|
|
||||||
QString dt;
|
|
||||||
if (lastDate == nowDate) {
|
|
||||||
dt = lastTime.toString(cTimeFormat());
|
|
||||||
} else if (lastDate.year() == nowDate.year() && lastDate.weekNumber() == nowDate.weekNumber()) {
|
|
||||||
dt = langDayOfWeek(lastDate);
|
|
||||||
} else {
|
|
||||||
dt = lastDate.toString(qsl("d.MM.yy"));
|
|
||||||
}
|
|
||||||
int32 dtWidth = st::dlgDateFont->width(dt);
|
|
||||||
rectForName.setWidth(rectForName.width() - dtWidth - st::dlgDateSkip);
|
|
||||||
p.setFont(st::dlgDateFont->f);
|
|
||||||
p.setPen((act ? st::dlgActiveDateColor : st::dlgDateColor)->p);
|
|
||||||
p.drawText(rectForName.left() + rectForName.width() + st::dlgDateSkip, rectForName.top() + st::msgNameFont->height - st::msgDateFont->descent, dt);
|
|
||||||
|
|
||||||
// draw check
|
|
||||||
if (_item->needCheck()) {
|
|
||||||
const style::sprite *check;
|
|
||||||
if (_item->id > 0) {
|
|
||||||
if (_item->unread()) {
|
|
||||||
check = act ? &st::dlgActiveCheckImg : &st::dlgCheckImg;
|
|
||||||
} else {
|
|
||||||
check = act ? &st::dlgActiveDblCheckImg : &st::dlgDblCheckImg;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
check = act ? &st::dlgActiveSendImg : &st::dlgSendImg;
|
|
||||||
}
|
|
||||||
rectForName.setWidth(rectForName.width() - check->pxWidth() - st::dlgCheckSkip);
|
|
||||||
p.drawPixmap(QPoint(rectForName.left() + rectForName.width() + st::dlgCheckLeft, rectForName.top() + st::dlgCheckTop), App::sprite(), *check);
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw unread
|
|
||||||
int32 lastWidth = namewidth;
|
|
||||||
_item->drawInDialog(p, QRect(nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, lastWidth, st::dlgFont->height), act, _cacheFor, _cache);
|
|
||||||
|
|
||||||
if (history->peer->isUser() && history->peer->isVerified()) {
|
|
||||||
rectForName.setWidth(rectForName.width() - st::verifiedCheck.pxWidth() - st::verifiedCheckPos.x());
|
|
||||||
p.drawSprite(rectForName.topLeft() + QPoint(qMin(history->peer->dialogName().maxWidth(), rectForName.width()), 0) + st::verifiedCheckPos, (act ? st::verifiedCheckInv : st::verifiedCheck));
|
|
||||||
}
|
|
||||||
|
|
||||||
p.setPen((act ? st::dlgActiveColor : st::dlgNameColor)->p);
|
|
||||||
history->peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
|
|
||||||
}
|
|
||||||
|
|
||||||
History::History(const PeerId &peerId)
|
History::History(const PeerId &peerId)
|
||||||
: peer(App::peer(peerId))
|
: peer(App::peer(peerId))
|
||||||
, mute(isNotifyMuted(peer->notify)) {
|
, mute(isNotifyMuted(peer->notify)) {
|
||||||
|
@ -981,107 +810,6 @@ ChannelHistory::~ChannelHistory() {
|
||||||
clearOnDestroy();
|
clearOnDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DialogsList::del(const PeerId &peerId, DialogRow *replacedBy) {
|
|
||||||
RowByPeer::iterator i = rowByPeer.find(peerId);
|
|
||||||
if (i == rowByPeer.cend()) return false;
|
|
||||||
|
|
||||||
DialogRow *row = i.value();
|
|
||||||
if (App::main()) {
|
|
||||||
emit App::main()->dialogRowReplaced(row, replacedBy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (row == current) {
|
|
||||||
current = row->next;
|
|
||||||
}
|
|
||||||
for (DialogRow *change = row->next; change != end; change = change->next) {
|
|
||||||
change->pos--;
|
|
||||||
}
|
|
||||||
end->pos--;
|
|
||||||
remove(row);
|
|
||||||
delete row;
|
|
||||||
--count;
|
|
||||||
rowByPeer.erase(i);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DialogsIndexed::peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) {
|
|
||||||
if (sortMode == DialogsSortByName) {
|
|
||||||
DialogRow *mainRow = list.adjustByName(peer);
|
|
||||||
if (!mainRow) return;
|
|
||||||
|
|
||||||
History *history = mainRow->history;
|
|
||||||
|
|
||||||
PeerData::NameFirstChars toRemove = oldChars, toAdd;
|
|
||||||
for (PeerData::NameFirstChars::const_iterator i = peer->chars.cbegin(), e = peer->chars.cend(); i != e; ++i) {
|
|
||||||
PeerData::NameFirstChars::iterator j = toRemove.find(*i);
|
|
||||||
if (j == toRemove.cend()) {
|
|
||||||
toAdd.insert(*i);
|
|
||||||
} else {
|
|
||||||
toRemove.erase(j);
|
|
||||||
DialogsIndex::iterator k = index.find(*i);
|
|
||||||
if (k != index.cend()) {
|
|
||||||
k.value()->adjustByName(peer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (PeerData::NameFirstChars::const_iterator i = toRemove.cbegin(), e = toRemove.cend(); i != e; ++i) {
|
|
||||||
DialogsIndex::iterator j = index.find(*i);
|
|
||||||
if (j != index.cend()) {
|
|
||||||
j.value()->del(peer->id, mainRow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!toAdd.isEmpty()) {
|
|
||||||
for (PeerData::NameFirstChars::const_iterator i = toAdd.cbegin(), e = toAdd.cend(); i != e; ++i) {
|
|
||||||
DialogsIndex::iterator j = index.find(*i);
|
|
||||||
if (j == index.cend()) {
|
|
||||||
j = index.insert(*i, new DialogsList(sortMode));
|
|
||||||
}
|
|
||||||
j.value()->addByName(history);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DialogsList::RowByPeer::const_iterator i = list.rowByPeer.find(peer->id);
|
|
||||||
if (i == list.rowByPeer.cend()) return;
|
|
||||||
|
|
||||||
DialogRow *mainRow = i.value();
|
|
||||||
History *history = mainRow->history;
|
|
||||||
|
|
||||||
PeerData::NameFirstChars toRemove = oldChars, toAdd;
|
|
||||||
for (PeerData::NameFirstChars::const_iterator i = peer->chars.cbegin(), e = peer->chars.cend(); i != e; ++i) {
|
|
||||||
PeerData::NameFirstChars::iterator j = toRemove.find(*i);
|
|
||||||
if (j == toRemove.cend()) {
|
|
||||||
toAdd.insert(*i);
|
|
||||||
} else {
|
|
||||||
toRemove.erase(j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (PeerData::NameFirstChars::const_iterator i = toRemove.cbegin(), e = toRemove.cend(); i != e; ++i) {
|
|
||||||
if (sortMode == DialogsSortByDate) history->removeChatListEntryByLetter(*i);
|
|
||||||
DialogsIndex::iterator j = index.find(*i);
|
|
||||||
if (j != index.cend()) {
|
|
||||||
j.value()->del(peer->id, mainRow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (PeerData::NameFirstChars::const_iterator i = toAdd.cbegin(), e = toAdd.cend(); i != e; ++i) {
|
|
||||||
DialogsIndex::iterator j = index.find(*i);
|
|
||||||
if (j == index.cend()) {
|
|
||||||
j = index.insert(*i, new DialogsList(sortMode));
|
|
||||||
}
|
|
||||||
DialogRow *row = j.value()->addToEnd(history);
|
|
||||||
if (sortMode == DialogsSortByDate) history->addChatListEntryByLetter(*i, row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DialogsIndexed::clear() {
|
|
||||||
for (DialogsIndex::iterator i = index.begin(), e = index.end(); i != e; ++i) {
|
|
||||||
delete i.value();
|
|
||||||
}
|
|
||||||
index.clear();
|
|
||||||
list.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
History *Histories::find(const PeerId &peerId) {
|
History *Histories::find(const PeerId &peerId) {
|
||||||
Map::const_iterator i = map.constFind(peerId);
|
Map::const_iterator i = map.constFind(peerId);
|
||||||
return (i == map.cend()) ? 0 : i.value();
|
return (i == map.cend()) ? 0 : i.value();
|
||||||
|
@ -2469,17 +2197,23 @@ void History::clearOnDestroy() {
|
||||||
clearBlocks(false);
|
clearBlocks(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<int32, int32> History::adjustByPosInChatsList(DialogsIndexed &indexed) {
|
QPair<int32, int32> History::adjustByPosInChatsList(Dialogs::IndexedList *indexed) {
|
||||||
DialogRow *lnk = mainChatListLink();
|
t_assert(indexed != nullptr);
|
||||||
int32 movedFrom = lnk->pos * st::dlgHeight;
|
Dialogs::Row *lnk = mainChatListLink();
|
||||||
indexed.adjustByPos(_chatListLinks);
|
int32 movedFrom = lnk->pos() * st::dlgHeight;
|
||||||
int32 movedTo = lnk->pos * st::dlgHeight;
|
indexed->adjustByPos(_chatListLinks);
|
||||||
|
int32 movedTo = lnk->pos() * st::dlgHeight;
|
||||||
return qMakePair(movedFrom, movedTo);
|
return qMakePair(movedFrom, movedTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
DialogRow *History::addToChatList(DialogsIndexed &indexed) {
|
int History::posInChatList() const {
|
||||||
|
return mainChatListLink()->pos();
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialogs::Row *History::addToChatList(Dialogs::IndexedList *indexed) {
|
||||||
|
t_assert(indexed != nullptr);
|
||||||
if (!inChatList()) {
|
if (!inChatList()) {
|
||||||
_chatListLinks = indexed.addToEnd(this);
|
_chatListLinks = indexed->addToEnd(this);
|
||||||
if (unreadCount) {
|
if (unreadCount) {
|
||||||
App::histories().unreadIncrement(unreadCount, mute);
|
App::histories().unreadIncrement(unreadCount, mute);
|
||||||
if (App::wnd()) App::wnd()->updateCounter();
|
if (App::wnd()) App::wnd()->updateCounter();
|
||||||
|
@ -2488,9 +2222,10 @@ DialogRow *History::addToChatList(DialogsIndexed &indexed) {
|
||||||
return mainChatListLink();
|
return mainChatListLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::removeFromChatList(DialogsIndexed &indexed) {
|
void History::removeFromChatList(Dialogs::IndexedList *indexed) {
|
||||||
|
t_assert(indexed != nullptr);
|
||||||
if (inChatList()) {
|
if (inChatList()) {
|
||||||
indexed.del(peer);
|
indexed->del(peer);
|
||||||
_chatListLinks.clear();
|
_chatListLinks.clear();
|
||||||
if (unreadCount) {
|
if (unreadCount) {
|
||||||
App::histories().unreadIncrement(-unreadCount, mute);
|
App::histories().unreadIncrement(-unreadCount, mute);
|
||||||
|
@ -2506,7 +2241,7 @@ void History::removeChatListEntryByLetter(QChar letter) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::addChatListEntryByLetter(QChar letter, DialogRow *row) {
|
void History::addChatListEntryByLetter(QChar letter, Dialogs::Row *row) {
|
||||||
t_assert(letter != 0);
|
t_assert(letter != 0);
|
||||||
if (inChatList()) {
|
if (inChatList()) {
|
||||||
_chatListLinks.insert(letter, row);
|
_chatListLinks.insert(letter, row);
|
||||||
|
|
|
@ -27,6 +27,7 @@ class HistoryItem;
|
||||||
typedef QMap<int32, HistoryItem*> SelectedItemSet;
|
typedef QMap<int32, HistoryItem*> SelectedItemSet;
|
||||||
|
|
||||||
#include "structs.h"
|
#include "structs.h"
|
||||||
|
#include "dialogs/dialogs_common.h"
|
||||||
|
|
||||||
enum NewMessageType {
|
enum NewMessageType {
|
||||||
NewMessageUnread,
|
NewMessageUnread,
|
||||||
|
@ -88,29 +89,6 @@ private:
|
||||||
|
|
||||||
class HistoryBlock;
|
class HistoryBlock;
|
||||||
|
|
||||||
struct DialogRow {
|
|
||||||
DialogRow(History *history = 0, DialogRow *prev = 0, DialogRow *next = 0, int32 pos = 0) : prev(prev), next(next), history(history), pos(pos), attached(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void paint(Painter &p, int32 w, bool act, bool sel, bool onlyBackground) const;
|
|
||||||
|
|
||||||
DialogRow *prev, *next;
|
|
||||||
History *history;
|
|
||||||
int32 pos;
|
|
||||||
void *attached; // for any attached data, for example View in contacts list
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FakeDialogRow {
|
|
||||||
FakeDialogRow(HistoryItem *item) : _item(item), _cacheFor(0), _cache(st::dlgRichMinWidth) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void paint(Painter &p, int32 w, bool act, bool sel, bool onlyBackground) const;
|
|
||||||
|
|
||||||
HistoryItem *_item;
|
|
||||||
mutable const HistoryItem *_cacheFor;
|
|
||||||
mutable Text _cache;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum HistoryMediaType {
|
enum HistoryMediaType {
|
||||||
MediaTypePhoto,
|
MediaTypePhoto,
|
||||||
MediaTypeVideo,
|
MediaTypeVideo,
|
||||||
|
@ -215,7 +193,11 @@ enum AddToOverviewMethod {
|
||||||
AddToOverviewBack, // when new messages slice was received and it is the last one, we index all media
|
AddToOverviewBack, // when new messages slice was received and it is the last one, we index all media
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DialogsIndexed;
|
namespace Dialogs {
|
||||||
|
class Row;
|
||||||
|
class IndexedList;
|
||||||
|
} // namespace Dialogs
|
||||||
|
|
||||||
class ChannelHistory;
|
class ChannelHistory;
|
||||||
class History {
|
class History {
|
||||||
public:
|
public:
|
||||||
|
@ -283,22 +265,19 @@ public:
|
||||||
void setLastMessage(HistoryItem *msg);
|
void setLastMessage(HistoryItem *msg);
|
||||||
void fixLastMessage(bool wasAtBottom);
|
void fixLastMessage(bool wasAtBottom);
|
||||||
|
|
||||||
typedef QMap<QChar, DialogRow*> ChatListLinksMap;
|
|
||||||
void setChatsListDate(const QDateTime &date);
|
void setChatsListDate(const QDateTime &date);
|
||||||
QPair<int32, int32> adjustByPosInChatsList(DialogsIndexed &indexed);
|
QPair<int32, int32> adjustByPosInChatsList(Dialogs::IndexedList *indexed);
|
||||||
uint64 sortKeyInChatList() const {
|
uint64 sortKeyInChatList() const {
|
||||||
return _sortKeyInChatList;
|
return _sortKeyInChatList;
|
||||||
}
|
}
|
||||||
bool inChatList() const {
|
bool inChatList() const {
|
||||||
return !_chatListLinks.isEmpty();
|
return !_chatListLinks.isEmpty();
|
||||||
}
|
}
|
||||||
int32 posInChatList() const {
|
int posInChatList() const;
|
||||||
return mainChatListLink()->pos;
|
Dialogs::Row *addToChatList(Dialogs::IndexedList *indexed);
|
||||||
}
|
void removeFromChatList(Dialogs::IndexedList *indexed);
|
||||||
DialogRow *addToChatList(DialogsIndexed &indexed);
|
|
||||||
void removeFromChatList(DialogsIndexed &indexed);
|
|
||||||
void removeChatListEntryByLetter(QChar letter);
|
void removeChatListEntryByLetter(QChar letter);
|
||||||
void addChatListEntryByLetter(QChar letter, DialogRow *row);
|
void addChatListEntryByLetter(QChar letter, Dialogs::Row *row);
|
||||||
void updateChatListEntry() const;
|
void updateChatListEntry() const;
|
||||||
|
|
||||||
MsgId minMsgId() const;
|
MsgId minMsgId() const;
|
||||||
|
@ -555,8 +534,8 @@ private:
|
||||||
}
|
}
|
||||||
Flags _flags;
|
Flags _flags;
|
||||||
|
|
||||||
ChatListLinksMap _chatListLinks;
|
Dialogs::RowsByLetter _chatListLinks;
|
||||||
DialogRow *mainChatListLink() const {
|
Dialogs::Row *mainChatListLink() const {
|
||||||
auto it = _chatListLinks.constFind(0);
|
auto it = _chatListLinks.constFind(0);
|
||||||
t_assert(it != _chatListLinks.cend());
|
t_assert(it != _chatListLinks.cend());
|
||||||
return it.value();
|
return it.value();
|
||||||
|
@ -661,280 +640,6 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DialogsSortMode {
|
|
||||||
DialogsSortByDate,
|
|
||||||
DialogsSortByName,
|
|
||||||
DialogsSortByAdd
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DialogsList {
|
|
||||||
DialogsList(DialogsSortMode sortMode) : begin(&last), end(&last), sortMode(sortMode), count(0), current(&last) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void adjustCurrent(int32 y, int32 h) const {
|
|
||||||
int32 pos = (y > 0) ? (y / h) : 0;
|
|
||||||
while (current->pos > pos && current != begin) {
|
|
||||||
current = current->prev;
|
|
||||||
}
|
|
||||||
while (current->pos + 1 <= pos && current->next != end) {
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void paint(Painter &p, int32 w, int32 hFrom, int32 hTo, PeerData *act, PeerData *sel, bool onlyBackground) const {
|
|
||||||
adjustCurrent(hFrom, st::dlgHeight);
|
|
||||||
|
|
||||||
DialogRow *drawFrom = current;
|
|
||||||
p.translate(0, drawFrom->pos * st::dlgHeight);
|
|
||||||
while (drawFrom != end && drawFrom->pos * st::dlgHeight < hTo) {
|
|
||||||
bool active = (drawFrom->history->peer == act) || (drawFrom->history->peer->migrateTo() && drawFrom->history->peer->migrateTo() == act);
|
|
||||||
bool selected = (drawFrom->history->peer == sel);
|
|
||||||
drawFrom->paint(p, w, active, selected, onlyBackground);
|
|
||||||
drawFrom = drawFrom->next;
|
|
||||||
p.translate(0, st::dlgHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DialogRow *rowAtY(int32 y, int32 h) const {
|
|
||||||
if (!count) return 0;
|
|
||||||
|
|
||||||
int32 pos = (y > 0) ? (y / h) : 0;
|
|
||||||
adjustCurrent(y, h);
|
|
||||||
return (pos == current->pos) ? current : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DialogRow *addToEnd(History *history) {
|
|
||||||
DialogRow *result = new DialogRow(history, end->prev, end, end->pos);
|
|
||||||
end->pos++;
|
|
||||||
if (begin == end) {
|
|
||||||
begin = current = result;
|
|
||||||
} else {
|
|
||||||
end->prev->next = result;
|
|
||||||
}
|
|
||||||
rowByPeer.insert(history->peer->id, result);
|
|
||||||
++count;
|
|
||||||
end->prev = result;
|
|
||||||
if (sortMode == DialogsSortByDate) {
|
|
||||||
adjustByPos(result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool insertBefore(DialogRow *row, DialogRow *before) {
|
|
||||||
if (row == before) return false;
|
|
||||||
|
|
||||||
if (current == row) current = row->prev;
|
|
||||||
|
|
||||||
DialogRow *updateTill = row->prev;
|
|
||||||
remove(row);
|
|
||||||
|
|
||||||
// insert row
|
|
||||||
row->next = before; // update row
|
|
||||||
row->prev = before->prev;
|
|
||||||
row->next->prev = row; // update row->next
|
|
||||||
if (row->prev) { // update row->prev
|
|
||||||
row->prev->next = row;
|
|
||||||
} else {
|
|
||||||
begin = row;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update y
|
|
||||||
for (DialogRow *n = row; n != updateTill; n = n->next) {
|
|
||||||
n->next->pos++;
|
|
||||||
row->pos--;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool insertAfter(DialogRow *row, DialogRow *after) {
|
|
||||||
if (row == after) return false;
|
|
||||||
|
|
||||||
if (current == row) current = row->next;
|
|
||||||
|
|
||||||
DialogRow *updateFrom = row->next;
|
|
||||||
remove(row);
|
|
||||||
|
|
||||||
// insert row
|
|
||||||
row->prev = after; // update row
|
|
||||||
row->next = after->next;
|
|
||||||
row->prev->next = row; // update row->prev
|
|
||||||
row->next->prev = row; // update row->next
|
|
||||||
|
|
||||||
// update y
|
|
||||||
for (DialogRow *n = updateFrom; n != row; n = n->next) {
|
|
||||||
n->pos--;
|
|
||||||
row->pos++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DialogRow *adjustByName(const PeerData *peer) {
|
|
||||||
if (sortMode != DialogsSortByName) return 0;
|
|
||||||
|
|
||||||
RowByPeer::iterator i = rowByPeer.find(peer->id);
|
|
||||||
if (i == rowByPeer.cend()) return 0;
|
|
||||||
|
|
||||||
DialogRow *row = i.value(), *change = row;
|
|
||||||
while (change->prev && change->prev->history->peer->name > peer->name) {
|
|
||||||
change = change->prev;
|
|
||||||
}
|
|
||||||
if (!insertBefore(row, change)) {
|
|
||||||
while (change->next != end && change->next->history->peer->name < peer->name) {
|
|
||||||
change = change->next;
|
|
||||||
}
|
|
||||||
insertAfter(row, change);
|
|
||||||
}
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
DialogRow *addByName(History *history) {
|
|
||||||
if (sortMode != DialogsSortByName) return 0;
|
|
||||||
|
|
||||||
DialogRow *row = addToEnd(history), *change = row;
|
|
||||||
const QString &peerName(history->peer->name);
|
|
||||||
while (change->prev && change->prev->history->peer->name.compare(peerName, Qt::CaseInsensitive) > 0) {
|
|
||||||
change = change->prev;
|
|
||||||
}
|
|
||||||
if (!insertBefore(row, change)) {
|
|
||||||
while (change->next != end && change->next->history->peer->name.compare(peerName, Qt::CaseInsensitive) < 0) {
|
|
||||||
change = change->next;
|
|
||||||
}
|
|
||||||
insertAfter(row, change);
|
|
||||||
}
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
void adjustByPos(DialogRow *row) {
|
|
||||||
if (sortMode != DialogsSortByDate) return;
|
|
||||||
|
|
||||||
DialogRow *change = row;
|
|
||||||
if (change != begin && begin->history->sortKeyInChatList() < row->history->sortKeyInChatList()) {
|
|
||||||
change = begin;
|
|
||||||
} else while (change->prev && change->prev->history->sortKeyInChatList() < row->history->sortKeyInChatList()) {
|
|
||||||
change = change->prev;
|
|
||||||
}
|
|
||||||
if (!insertBefore(row, change)) {
|
|
||||||
if (change->next != end && end->prev->history->sortKeyInChatList() > row->history->sortKeyInChatList()) {
|
|
||||||
change = end->prev;
|
|
||||||
} else while (change->next != end && change->next->history->sortKeyInChatList() > row->history->sortKeyInChatList()) {
|
|
||||||
change = change->next;
|
|
||||||
}
|
|
||||||
insertAfter(row, change);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool del(const PeerId &peerId, DialogRow *replacedBy = 0);
|
|
||||||
|
|
||||||
void remove(DialogRow *row) {
|
|
||||||
row->next->prev = row->prev; // update row->next
|
|
||||||
if (row->prev) { // update row->prev
|
|
||||||
row->prev->next = row->next;
|
|
||||||
} else {
|
|
||||||
begin = row->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
while (begin != end) {
|
|
||||||
current = begin;
|
|
||||||
begin = begin->next;
|
|
||||||
delete current;
|
|
||||||
}
|
|
||||||
current = begin;
|
|
||||||
rowByPeer.clear();
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
~DialogsList() {
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
DialogRow last;
|
|
||||||
DialogRow *begin, *end;
|
|
||||||
DialogsSortMode sortMode;
|
|
||||||
int32 count;
|
|
||||||
|
|
||||||
typedef QHash<PeerId, DialogRow*> RowByPeer;
|
|
||||||
RowByPeer rowByPeer;
|
|
||||||
|
|
||||||
mutable DialogRow *current; // cache
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DialogsIndexed {
|
|
||||||
DialogsIndexed(DialogsSortMode sortMode) : sortMode(sortMode), list(sortMode) {
|
|
||||||
}
|
|
||||||
|
|
||||||
History::ChatListLinksMap addToEnd(History *history) {
|
|
||||||
History::ChatListLinksMap result;
|
|
||||||
DialogsList::RowByPeer::const_iterator i = list.rowByPeer.find(history->peer->id);
|
|
||||||
if (i == list.rowByPeer.cend()) {
|
|
||||||
result.insert(0, list.addToEnd(history));
|
|
||||||
for (PeerData::NameFirstChars::const_iterator i = history->peer->chars.cbegin(), e = history->peer->chars.cend(); i != e; ++i) {
|
|
||||||
DialogsIndex::iterator j = index.find(*i);
|
|
||||||
if (j == index.cend()) {
|
|
||||||
j = index.insert(*i, new DialogsList(sortMode));
|
|
||||||
}
|
|
||||||
result.insert(*i, j.value()->addToEnd(history));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
DialogRow *addByName(History *history) {
|
|
||||||
DialogsList::RowByPeer::const_iterator i = list.rowByPeer.constFind(history->peer->id);
|
|
||||||
if (i != list.rowByPeer.cend()) {
|
|
||||||
return i.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
DialogRow *res = list.addByName(history);
|
|
||||||
for (PeerData::NameFirstChars::const_iterator i = history->peer->chars.cbegin(), e = history->peer->chars.cend(); i != e; ++i) {
|
|
||||||
DialogsIndex::iterator j = index.find(*i);
|
|
||||||
if (j == index.cend()) {
|
|
||||||
j = index.insert(*i, new DialogsList(sortMode));
|
|
||||||
}
|
|
||||||
j.value()->addByName(history);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void adjustByPos(const History::ChatListLinksMap &links) {
|
|
||||||
for (History::ChatListLinksMap::const_iterator i = links.cbegin(), e = links.cend(); i != e; ++i) {
|
|
||||||
if (i.key() == QChar(0)) {
|
|
||||||
list.adjustByPos(i.value());
|
|
||||||
} else {
|
|
||||||
DialogsIndex::iterator j = index.find(i.key());
|
|
||||||
if (j != index.cend()) {
|
|
||||||
j.value()->adjustByPos(i.value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
|
|
||||||
|
|
||||||
void del(const PeerData *peer, DialogRow *replacedBy = 0) {
|
|
||||||
if (list.del(peer->id, replacedBy)) {
|
|
||||||
for (PeerData::NameFirstChars::const_iterator i = peer->chars.cbegin(), e = peer->chars.cend(); i != e; ++i) {
|
|
||||||
DialogsIndex::iterator j = index.find(*i);
|
|
||||||
if (j != index.cend()) {
|
|
||||||
j.value()->del(peer->id, replacedBy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~DialogsIndexed() {
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
DialogsSortMode sortMode;
|
|
||||||
DialogsList list;
|
|
||||||
typedef QMap<QChar, DialogsList*> DialogsIndex;
|
|
||||||
DialogsIndex index;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HistoryBlock {
|
class HistoryBlock {
|
||||||
public:
|
public:
|
||||||
HistoryBlock(History *hist) : y(0), height(0), history(hist), _indexInHistory(-1) {
|
HistoryBlock(History *hist) : y(0), height(0), history(hist), _indexInHistory(-1) {
|
||||||
|
|
|
@ -61,7 +61,7 @@ Result::Result(const Creator &creator) : _queryId(creator.queryId), _type(creato
|
||||||
|
|
||||||
UniquePointer<Result> Result::create(uint64 queryId, const MTPBotInlineResult &mtpData) {
|
UniquePointer<Result> Result::create(uint64 queryId, const MTPBotInlineResult &mtpData) {
|
||||||
using StringToTypeMap = QMap<QString, Result::Type>;
|
using StringToTypeMap = QMap<QString, Result::Type>;
|
||||||
StaticNeverFreedPointer<StringToTypeMap> stringToTypeMap{ ([]() -> StringToTypeMap* {
|
static StaticNeverFreedPointer<StringToTypeMap> stringToTypeMap{ ([]() -> StringToTypeMap* {
|
||||||
auto result = MakeUnique<StringToTypeMap>();
|
auto result = MakeUnique<StringToTypeMap>();
|
||||||
result->insert(qsl("photo"), Result::Type::Photo);
|
result->insert(qsl("photo"), Result::Type::Photo);
|
||||||
result->insert(qsl("video"), Result::Type::Video);
|
result->insert(qsl("video"), Result::Type::Video);
|
||||||
|
@ -75,7 +75,7 @@ UniquePointer<Result> Result::create(uint64 queryId, const MTPBotInlineResult &m
|
||||||
return result.release();
|
return result.release();
|
||||||
})() };
|
})() };
|
||||||
|
|
||||||
auto getInlineResultType = [&stringToTypeMap](const MTPBotInlineResult &inlineResult) -> Type {
|
auto getInlineResultType = [](const MTPBotInlineResult &inlineResult) -> Type {
|
||||||
QString type;
|
QString type;
|
||||||
switch (inlineResult.type()) {
|
switch (inlineResult.type()) {
|
||||||
case mtpc_botInlineResult: type = qs(inlineResult.c_botInlineResult().vtype); break;
|
case mtpc_botInlineResult: type = qs(inlineResult.c_botInlineResult().vtype); break;
|
||||||
|
|
|
@ -1363,11 +1363,11 @@ void MainWidget::clearSelectedItems() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DialogsIndexed &MainWidget::contactsList() {
|
Dialogs::IndexedList *MainWidget::contactsList() {
|
||||||
return dialogs.contactsList();
|
return dialogs.contactsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
DialogsIndexed &MainWidget::dialogsList() {
|
Dialogs::IndexedList *MainWidget::dialogsList() {
|
||||||
return dialogs.dialogsList();
|
return dialogs.dialogsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2653,7 +2653,7 @@ QRect MainWidget::historyRect() const {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::dlgUpdated(DialogRow *row) {
|
void MainWidget::dlgUpdated(Dialogs::Row *row) {
|
||||||
if (row) {
|
if (row) {
|
||||||
dialogs.dlgUpdated(row);
|
dialogs.dlgUpdated(row);
|
||||||
} else if (_peerInStack) {
|
} else if (_peerInStack) {
|
||||||
|
|
|
@ -28,8 +28,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "playerwidget.h"
|
#include "playerwidget.h"
|
||||||
|
|
||||||
class Window;
|
class Window;
|
||||||
struct DialogRow;
|
|
||||||
|
|
||||||
class ApiWrap;
|
class ApiWrap;
|
||||||
class MainWidget;
|
class MainWidget;
|
||||||
class ConfirmBox;
|
class ConfirmBox;
|
||||||
|
@ -39,6 +37,10 @@ class ProfileWidget;
|
||||||
class OverviewWidget;
|
class OverviewWidget;
|
||||||
class PlayerWidget;
|
class PlayerWidget;
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
class Row;
|
||||||
|
} // namespace Dialogs
|
||||||
|
|
||||||
class TopBarWidget : public TWidget {
|
class TopBarWidget : public TWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -257,7 +259,7 @@ public:
|
||||||
|
|
||||||
void createDialog(History *history);
|
void createDialog(History *history);
|
||||||
void removeDialog(History *history);
|
void removeDialog(History *history);
|
||||||
void dlgUpdated(DialogRow *row = 0);
|
void dlgUpdated(Dialogs::Row *row = nullptr);
|
||||||
void dlgUpdated(History *row, MsgId msgId);
|
void dlgUpdated(History *row, MsgId msgId);
|
||||||
|
|
||||||
void windowShown();
|
void windowShown();
|
||||||
|
@ -350,8 +352,8 @@ public:
|
||||||
void deleteSelectedItems();
|
void deleteSelectedItems();
|
||||||
void clearSelectedItems();
|
void clearSelectedItems();
|
||||||
|
|
||||||
DialogsIndexed &contactsList();
|
Dialogs::IndexedList *contactsList();
|
||||||
DialogsIndexed &dialogsList();
|
Dialogs::IndexedList *dialogsList();
|
||||||
|
|
||||||
void sendMessage(History *hist, const QString &text, MsgId replyTo, bool broadcast, bool silent, WebPageId webPageId = 0);
|
void sendMessage(History *hist, const QString &text, MsgId replyTo, bool broadcast, bool silent, WebPageId webPageId = 0);
|
||||||
void saveRecentHashtags(const QString &text);
|
void saveRecentHashtags(const QString &text);
|
||||||
|
@ -477,7 +479,7 @@ signals:
|
||||||
void peerUpdated(PeerData *peer);
|
void peerUpdated(PeerData *peer);
|
||||||
void peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
|
void peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
|
||||||
void peerPhotoChanged(PeerData *peer);
|
void peerPhotoChanged(PeerData *peer);
|
||||||
void dialogRowReplaced(DialogRow *oldRow, DialogRow *newRow);
|
void dialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow);
|
||||||
void dialogsUpdated();
|
void dialogsUpdated();
|
||||||
void stickersUpdated();
|
void stickersUpdated();
|
||||||
void savedGifsUpdated();
|
void savedGifsUpdated();
|
||||||
|
|
|
@ -946,7 +946,7 @@ void FlatTextarea::keyPressEvent(QKeyEvent *e) {
|
||||||
if (ctrl && _submitSettings != SubmitSettings::None && _submitSettings != SubmitSettings::Enter) {
|
if (ctrl && _submitSettings != SubmitSettings::None && _submitSettings != SubmitSettings::Enter) {
|
||||||
enterSubmit = true;
|
enterSubmit = true;
|
||||||
}
|
}
|
||||||
if (!ctrl && _submitSettings != SubmitSettings::None && _submitSettings != SubmitSettings::CtrlEnter) {
|
if (!ctrl && !shift && _submitSettings != SubmitSettings::None && _submitSettings != SubmitSettings::CtrlEnter) {
|
||||||
enterSubmit = true;
|
enterSubmit = true;
|
||||||
}
|
}
|
||||||
bool enter = (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return);
|
bool enter = (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return);
|
||||||
|
|
|
@ -1341,7 +1341,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
const ClickHandlerPtr &link(int32 x, int32 y, int32 w, style::align align) {
|
const ClickHandlerPtr &link(int32 x, int32 y, int32 w, style::align align) {
|
||||||
StaticNeverFreedPointer<ClickHandlerPtr> zero(new ClickHandlerPtr());
|
static StaticNeverFreedPointer<ClickHandlerPtr> zero(new ClickHandlerPtr());
|
||||||
|
|
||||||
_lnkX = x;
|
_lnkX = x;
|
||||||
_lnkY = y;
|
_lnkY = y;
|
||||||
|
|
|
@ -168,6 +168,9 @@ SOURCES += \
|
||||||
./SourceFiles/boxes/sessionsbox.cpp \
|
./SourceFiles/boxes/sessionsbox.cpp \
|
||||||
./SourceFiles/boxes/stickersetbox.cpp \
|
./SourceFiles/boxes/stickersetbox.cpp \
|
||||||
./SourceFiles/boxes/usernamebox.cpp \
|
./SourceFiles/boxes/usernamebox.cpp \
|
||||||
|
./SourceFiles/dialogs/dialogs_indexed_list.cpp \
|
||||||
|
./SourceFiles/dialogs/dialogs_layout.cpp \
|
||||||
|
./SourceFiles/dialogs/dialogs_list.cpp \
|
||||||
./SourceFiles/inline_bots/inline_bot_layout_internal.cpp \
|
./SourceFiles/inline_bots/inline_bot_layout_internal.cpp \
|
||||||
./SourceFiles/inline_bots/inline_bot_layout_item.cpp \
|
./SourceFiles/inline_bots/inline_bot_layout_item.cpp \
|
||||||
./SourceFiles/inline_bots/inline_bot_result.cpp \
|
./SourceFiles/inline_bots/inline_bot_result.cpp \
|
||||||
|
@ -274,6 +277,11 @@ HEADERS += \
|
||||||
./SourceFiles/boxes/sessionsbox.h \
|
./SourceFiles/boxes/sessionsbox.h \
|
||||||
./SourceFiles/boxes/stickersetbox.h \
|
./SourceFiles/boxes/stickersetbox.h \
|
||||||
./SourceFiles/boxes/usernamebox.h \
|
./SourceFiles/boxes/usernamebox.h \
|
||||||
|
./SourceFiles/dialogs/dialogs_common.h \
|
||||||
|
./SourceFiles/dialogs/dialogs_indexed_list.h \
|
||||||
|
./SourceFiles/dialogs/dialogs_layout.h \
|
||||||
|
./SourceFiles/dialogs/dialogs_list.h \
|
||||||
|
./SourceFiles/dialogs/dialogs_row.h \
|
||||||
./SourceFiles/inline_bots/inline_bot_layout_internal.h \
|
./SourceFiles/inline_bots/inline_bot_layout_internal.h \
|
||||||
./SourceFiles/inline_bots/inline_bot_layout_item.h \
|
./SourceFiles/inline_bots/inline_bot_layout_item.h \
|
||||||
./SourceFiles/inline_bots/inline_bot_result.h \
|
./SourceFiles/inline_bots/inline_bot_result.h \
|
||||||
|
|
|
@ -1064,6 +1064,9 @@
|
||||||
<ClCompile Include="SourceFiles\boxes\stickersetbox.cpp" />
|
<ClCompile Include="SourceFiles\boxes\stickersetbox.cpp" />
|
||||||
<ClCompile Include="SourceFiles\boxes\usernamebox.cpp" />
|
<ClCompile Include="SourceFiles\boxes\usernamebox.cpp" />
|
||||||
<ClCompile Include="SourceFiles\dialogswidget.cpp" />
|
<ClCompile Include="SourceFiles\dialogswidget.cpp" />
|
||||||
|
<ClCompile Include="SourceFiles\dialogs\dialogs_indexed_list.cpp" />
|
||||||
|
<ClCompile Include="SourceFiles\dialogs\dialogs_layout.cpp" />
|
||||||
|
<ClCompile Include="SourceFiles\dialogs\dialogs_list.cpp" />
|
||||||
<ClCompile Include="SourceFiles\dropdown.cpp" />
|
<ClCompile Include="SourceFiles\dropdown.cpp" />
|
||||||
<ClCompile Include="SourceFiles\facades.cpp" />
|
<ClCompile Include="SourceFiles\facades.cpp" />
|
||||||
<ClCompile Include="SourceFiles\fileuploader.cpp" />
|
<ClCompile Include="SourceFiles\fileuploader.cpp" />
|
||||||
|
@ -1223,6 +1226,11 @@
|
||||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/basic_types.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui"</Command>
|
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/basic_types.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui"</Command>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
|
<ClInclude Include="SourceFiles\dialogs\dialogs_common.h" />
|
||||||
|
<ClInclude Include="SourceFiles\dialogs\dialogs_indexed_list.h" />
|
||||||
|
<ClInclude Include="SourceFiles\dialogs\dialogs_layout.h" />
|
||||||
|
<ClInclude Include="SourceFiles\dialogs\dialogs_list.h" />
|
||||||
|
<ClInclude Include="SourceFiles\dialogs\dialogs_row.h" />
|
||||||
<ClInclude Include="SourceFiles\inline_bots\inline_bot_layout_internal.h" />
|
<ClInclude Include="SourceFiles\inline_bots\inline_bot_layout_internal.h" />
|
||||||
<ClInclude Include="SourceFiles\inline_bots\inline_bot_layout_item.h" />
|
<ClInclude Include="SourceFiles\inline_bots\inline_bot_layout_item.h" />
|
||||||
<ClInclude Include="SourceFiles\inline_bots\inline_bot_result.h" />
|
<ClInclude Include="SourceFiles\inline_bots\inline_bot_result.h" />
|
||||||
|
|
|
@ -61,6 +61,9 @@
|
||||||
<Filter Include="Resources\langs">
|
<Filter Include="Resources\langs">
|
||||||
<UniqueIdentifier>{67311646-a8af-4626-976d-0a5733bf90e8}</UniqueIdentifier>
|
<UniqueIdentifier>{67311646-a8af-4626-976d-0a5733bf90e8}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="dialogs">
|
||||||
|
<UniqueIdentifier>{405e59c2-0800-4f73-b975-1749c8c36e87}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="SourceFiles\main.cpp">
|
<ClCompile Include="SourceFiles\main.cpp">
|
||||||
|
@ -1017,6 +1020,15 @@
|
||||||
<ClCompile Include="SourceFiles\serialize\serialize_common.cpp">
|
<ClCompile Include="SourceFiles\serialize\serialize_common.cpp">
|
||||||
<Filter>serialize</Filter>
|
<Filter>serialize</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="SourceFiles\dialogs\dialogs_layout.cpp">
|
||||||
|
<Filter>dialogs</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="SourceFiles\dialogs\dialogs_list.cpp">
|
||||||
|
<Filter>dialogs</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="SourceFiles\dialogs\dialogs_indexed_list.cpp">
|
||||||
|
<Filter>dialogs</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="SourceFiles\stdafx.h">
|
<ClInclude Include="SourceFiles\stdafx.h">
|
||||||
|
@ -1139,6 +1151,21 @@
|
||||||
<ClInclude Include="SourceFiles\serialize\serialize_common.h">
|
<ClInclude Include="SourceFiles\serialize\serialize_common.h">
|
||||||
<Filter>serialize</Filter>
|
<Filter>serialize</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="SourceFiles\dialogs\dialogs_layout.h">
|
||||||
|
<Filter>dialogs</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="SourceFiles\dialogs\dialogs_list.h">
|
||||||
|
<Filter>dialogs</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="SourceFiles\dialogs\dialogs_indexed_list.h">
|
||||||
|
<Filter>dialogs</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="SourceFiles\dialogs\dialogs_common.h">
|
||||||
|
<Filter>dialogs</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="SourceFiles\dialogs\dialogs_row.h">
|
||||||
|
<Filter>dialogs</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<CustomBuild Include="SourceFiles\application.h">
|
<CustomBuild Include="SourceFiles\application.h">
|
||||||
|
|
Loading…
Reference in New Issue