version 0.5.6 with serverside messages search, win version only

This commit is contained in:
John Preston 2014-07-04 15:12:54 +04:00
parent ce84c603c2
commit 29d6bf46c8
35 changed files with 3294 additions and 2062 deletions

View File

@ -122,6 +122,8 @@ lng_signup_firstname: "First Name";
lng_signup_lastname: "Last Name";
lng_dlg_filter: "Search";
lng_dlg_conversations: "Conversations";
lng_dlg_messages: "Messages";
lng_dlg_new_group_name: "Group name";
lng_dlg_create_group: "Create";

View File

@ -153,11 +153,12 @@ btnDefBig: flatButton(btnDefFlat) {
overFont: font(23px);
height: 56px;
}
btnNextBG: #2fa9e2;
btnDefNext: flatButton(btnDefFlat) {
color: white;
overColor: white;
downColor: white;
bgColor: #2fa9e2;
bgColor: btnNextBG;
overBgColor: #279ad0;
downBgColor: #279ad0;
}
@ -593,6 +594,23 @@ dlgPaddingVer: 8px;
dlgHeight: 62px;
dlgPhotoPadding: 12px;
dlgState: switcher {
border: 2px;
borderColor: btnNextBG;
bgColor: #fff;
bgHovered: btnWhiteHover;
bgActive: btnNextBG;
height: 34px;
font: font(fsize);
textColor: btnYesColor;
activeColor: #fff;
duration: 200;
}
dlgSep: 8px;
dlgShadowColor: rgba(0, 0, 0, 24);//#ebebeb
@ -709,6 +727,24 @@ topBarActionSkip: 13px;
topBarSelectedPos: point(18px, 18px);
historyBG: #dfe4e8;
historyToEnd: iconedButton(btnDefIconed) {
bgColor: transparent;
overBgColor: transparent;
icon: sprite(252px, 41px, 44px, 44px);
iconPos: point(0px, 0px);
downIcon: sprite(252px, 41px, 44px, 44px);
downIconPos: point(0px, 0px);
width: 44px;
height: 44px;
}
historyToEndSkip: 10px;
activeFadeInDuration: 500;
activeFadeOutDuration: 3000;
msgMaxWidth: 550px;
msgFont: font(fsize);
msgNameFont: font(fsize semibold);
@ -765,9 +801,9 @@ msgDateSpace: 19px;
msgDateCheckSpace: 4px;
msgDateDelta: point(2px, 5px);
msgImgSendingRect: sprite(280px, 40px, 20px, 20px);
msgImgSendingRect: sprite(320px, 65px, 20px, 20px);
msgImgCheckRect: sprite(280px, 20px, 20px, 20px);
msgImgDblCheckRect: sprite(260px, 40px, 20px, 20px);
msgImgDblCheckRect: sprite(300px, 65px, 20px, 20px);
msgDateImgDelta: 4px;
msgDateImgColor: #fff;
msgDateImgBg: #00000054;
@ -877,8 +913,8 @@ btnAttachDocument: iconedButton(btnDefIconed) {
height: 46px;
}
btnAttachPhoto: iconedButton(btnAttachDocument) {
icon: sprite(278px, 68px, 24px, 24px);
downIcon: sprite(278px, 68px, 24px, 24px);
icon: sprite(113px, 0px, 24px, 24px);
downIcon: sprite(113px, 0px, 24px, 24px);
}
btnAttachEmoji: iconedButton(btnAttachDocument) {
overBgColor: white;
@ -957,6 +993,10 @@ btnAddContact: iconedButton(btnNewGroup) {
icon: sprite(188px, 93px, 18px, 18px);
downIcon: sprite(188px, 93px, 18px, 18px);
}
btnCancelSearch: iconedButton(btnNewGroup) {
icon: sprite(188px, 43px, 18px, 18px);
downIcon: sprite(188px, 43px, 18px, 18px);
}
notifyBG: white;
notifyBorder: #f1f1f1;
@ -1245,8 +1285,8 @@ dropdownAttachDocument: iconedButton(btnAttachDocument) {
downTextPos: point(50px, 14px);
}
dropdownAttachPhoto: iconedButton(dropdownAttachDocument) {
icon: sprite(278px, 68px, 24px, 24px);
downIcon: sprite(278px, 68px, 24px, 24px);
icon: sprite(113px, 0px, 24px, 24px);
downIcon: sprite(113px, 0px, 24px, 24px);
}
dragFont: font(28px semibold);

View File

@ -229,3 +229,20 @@ flatLabel {
width: number;
align: align;
}
switcher {
border: number;
borderColor: color;
bgColor: color;
bgHovered: color;
bgActive: color;
height: number;
font: font;
textColor: color;
activeColor: color;
duration: number;
}

View File

@ -3,9 +3,9 @@
#define MyAppShortName "Telegram"
#define MyAppName "Telegram Win (Unofficial)"
#define MyAppVersion "0.5.4"
#define MyAppVersionZero "0.5.4"
#define MyAppFullVersion "0.5.4.0"
#define MyAppVersion "0.5.6"
#define MyAppVersionZero "0.5.6"
#define MyAppFullVersion "0.5.6.0"
#define MyAppPublisher "Telegram (Unofficial)"
#define MyAppURL "https://tdesktop.com"
#define MyAppExeName "Telegram.exe"

View File

@ -508,7 +508,7 @@ namespace App {
}
}
for (QMap<int32, int32>::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) {
histories().addToBack(v[*i], newMsgs);
histories().addToBack(v[*i], newMsgs ? 1 : 0);
}
}
@ -557,9 +557,6 @@ namespace App {
if (j != msgsData.cend()) {
History *h = (*j)->history();
(*j)->destroy();
if (h->isEmpty()) {
if (App::main()) App::main()->checkPeerHistory(h->peer);
}
}
}
}
@ -1100,23 +1097,26 @@ namespace App {
return 0;
}
bool historyRegItem(HistoryItem *item) {
HistoryItem *historyRegItem(HistoryItem *item) {
MsgsData::const_iterator i = msgsData.constFind(item->id);
if (i == msgsData.cend()) {
msgsData.insert(item->id, item);
if (item->id > ::maxMsgId) ::maxMsgId = item->id;
return true;
return 0;
}
return (i.value() == item);
if (i.value() != item && !i.value()->block() && item->block()) { // replace search item
item->history()->itemReplaced(i.value(), item);
if (App::main()) {
emit App::main()->historyItemReplaced(i.value(), item);
}
delete i.value();
msgsData.insert(item->id, item);
return 0;
}
return (i.value() == item) ? 0 : i.value();
}
void historyUnregItem(HistoryItem *item) {
MsgsData::iterator i = msgsData.find(item->id);
if (i != msgsData.cend()) {
if (i.value() == item) {
msgsData.erase(i);
}
}
void historyItemDetached(HistoryItem *item) {
if (::hoveredItem == item) {
hoveredItem(0);
}
@ -1135,13 +1135,32 @@ namespace App {
if (::mousedItem == item) {
mousedItem(0);
}
}
void historyUnregItem(HistoryItem *item) {
MsgsData::iterator i = msgsData.find(item->id);
if (i != msgsData.cend()) {
if (i.value() == item) {
msgsData.erase(i);
}
}
historyItemDetached(item);
if (App::main()) {
emit App::main()->historyItemDeleted(item);
}
}
void historyClearMsgs() {
QVector<HistoryItem*> toDelete;
for (MsgsData::const_iterator i = msgsData.cbegin(), e = msgsData.cend(); i != e; ++i) {
if ((*i)->detached()) {
toDelete.push_back(*i);
}
}
msgsData.clear();
for (int i = 0, l = toDelete.size(); i < l; ++i) {
delete toDelete[i];
}
::maxMsgId = 0;
::hoveredItem = ::pressedItem = ::hoveredLinkItem = ::pressedLinkItem = ::contextItem = 0;
}
@ -1224,6 +1243,12 @@ namespace App {
textlnkOver(TextLinkPtr());
textlnkDown(TextLinkPtr());
if (completely && App::main()) {
App::main()->disconnect(SIGNAL(historyItemDeleted(HistoryItem *)));
}
histories().clear();
if (completely) {
LOG(("Deleting sound.."));
delete newMsgSound;
@ -1242,12 +1267,6 @@ namespace App {
clearStorageImages();
}
if (App::main()) {
App::main()->disconnect(SIGNAL(historyItemDeleted(HistoryItem*)));
}
histories().clear();
serviceImageCacheSize = imageCacheSize();
}

View File

@ -116,7 +116,8 @@ namespace App {
History *history(const PeerId &peer, int32 unreadCnt = 0);
History *historyLoaded(const PeerId &peer);
HistoryItem *histItemById(MsgId itemId);
bool historyRegItem(HistoryItem *item);
HistoryItem *historyRegItem(HistoryItem *item);
void historyItemDetached(HistoryItem *item);
void historyUnregItem(HistoryItem *item);
void historyClearMsgs();
void historyClearItems();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -210,7 +210,7 @@ void ContactsInner::chooseParticipant() {
}
if (r) {
App::wnd()->hideSettings(true);
App::main()->showPeer(r->history->peer->id, false, true);
App::main()->showPeer(r->history->peer->id, 0, false, true);
App::wnd()->hideLayer();
}

View File

@ -438,6 +438,15 @@ QVector<MTPInputUser> NewGroupInner::selectedInputs() {
return result;
}
PeerData *NewGroupInner::selectedUser() {
for (ContactsData::const_iterator i = _contactsData.cbegin(), e = _contactsData.cend(); i != e; ++i) {
if (i.value()->check) {
return i.key();
}
}
return 0;
}
NewGroupBox::NewGroupBox() : _scroll(this, st::newGroupScroll), _inner(),
_filter(this, st::contactsFilter, lang(lng_participant_filter)),
_next(this, lang(lng_create_group_next), st::btnSelectDone),
@ -579,13 +588,15 @@ void NewGroupBox::onClose() {
void NewGroupBox::onNext() {
MTPVector<MTPInputUser> users(MTP_vector<MTPInputUser>(_inner.selectedInputs()));
if (users.c_vector().v.isEmpty()) {
const QVector<MTPInputUser> &v(users.c_vector().v);
if (v.isEmpty()) {
_filter.setFocus();
_filter.notaBene();
return;
} else if (v.size() == 1) {
App::main()->showPeer(_inner.selectedUser()->id);
} else {
App::wnd()->replaceLayer(new CreateGroupBox(users));
}
App::wnd()->replaceLayer(new CreateGroupBox(users));
}
void NewGroupBox::onScroll() {

View File

@ -39,6 +39,7 @@ public:
void selectSkipPage(int32 h, int32 dir);
QVector<MTPInputUser> selectedInputs();
PeerData *selectedUser();
void loadProfilePhotos(int32 yFrom);

View File

@ -17,8 +17,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
*/
#pragma once
static const int32 AppVersion = 5005;
static const wchar_t *AppVersionStr = L"0.5.5";
static const int32 AppVersion = 5006;
static const wchar_t *AppVersionStr = L"0.5.6";
#ifdef Q_OS_WIN
static const wchar_t *AppName = L"Telegram Win (Unofficial)";
#else
@ -56,7 +56,12 @@ enum {
LocalEncryptSaltSize = 32, // 256 bit
LocalEncryptKeySize = 256, // 2048 bit
AnimationTimerDelta = 7,
SaveRecentEmojisTimeout = 3000, // 3 secs
AutoSearchTimeout = 1500, // 1.5 secs
SearchPerPage = 50,
};
#ifdef Q_OS_WIN

View File

@ -26,11 +26,16 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
#include "boxes/newgroupbox.h"
DialogsListWidget::DialogsListWidget(QWidget *parent, MainWidget *main) : QWidget(parent),
dialogs(false), contactsNoDialogs(true), contacts(true), sel(0), contactSel(false), selByMouse(false), filteredSel(-1) {
dialogs(false), contactsNoDialogs(true), contacts(true), sel(0), contactSel(false), selByMouse(false), filteredSel(-1), searchedSel(-1), _state(DefaultState) {
connect(main, SIGNAL(dialogToTop(const History::DialogLinks &)), this, SLOT(onDialogToTop(const History::DialogLinks &)));
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(dialogRowReplaced(DialogRow *, DialogRow *)), this, SLOT(onDialogRowReplaced(DialogRow *, DialogRow *)));
connect(main, SIGNAL(historyItemReplaced(HistoryItem *, HistoryItem *)), this, SLOT(onItemReplaced(HistoryItem *, HistoryItem *)));
connect(main, SIGNAL(historyItemDeleted(HistoryItem *)), this, SLOT(onItemRemoved(HistoryItem *)));
_updateSearchTimer.setSingleShot(true);
connect(&_updateSearchTimer, SIGNAL(timeout()), this, SIGNAL(searchMessages()));
}
void DialogsListWidget::paintEvent(QPaintEvent *e) {
@ -42,7 +47,7 @@ void DialogsListWidget::paintEvent(QPaintEvent *e) {
p.setClipRect(r);
}
if (filter.isEmpty()) {
if (_state == DefaultState) {
int32 otherStart = dialogs.list.count * st::dlgHeight;
PeerData *active = App::main()->activePeer(), *selected = sel ? sel->history->peer : 0;
if (otherStart) {
@ -53,21 +58,40 @@ void DialogsListWidget::paintEvent(QPaintEvent *e) {
} else if (!otherStart) {
// .. paint no dialogs found
}
} else {
if (filtered.isEmpty()) {
} else if (_state == FilteredState) {
if (filterResults.isEmpty()) {
// .. paint no dialogs
} else {
int32 from = r.top() / int32(st::dlgHeight);
if (from < 0) from = 0;
if (from < filtered.size()) {
if (from < filterResults.size()) {
int32 to = (r.bottom() / int32(st::dlgHeight)) + 1, w = width();
if (to > filtered.size()) to = filtered.size();
if (to > filterResults.size()) to = filterResults.size();
p.translate(0, from * st::dlgHeight);
for (; from < to; ++from) {
bool active = (filtered[from]->history->peer == App::main()->activePeer());
bool active = (filterResults[from]->history->peer == App::main()->activePeer());
bool selected = (from == filteredSel);
filtered[from]->paint(p, w, active, selected);
filterResults[from]->paint(p, w, active, selected);
p.translate(0, st::dlgHeight);
}
}
}
} else if (_state == SearchedState) {
if (searchResults.isEmpty()) {
// .. paint no dialogs
} else {
int32 from = r.top() / int32(st::dlgHeight);
if (from < 0) from = 0;
if (from < searchResults.size()) {
int32 to = (r.bottom() / int32(st::dlgHeight)) + 1, w = width();
if (to > searchResults.size()) to = searchResults.size();
p.translate(0, from * st::dlgHeight);
for (; from < to; ++from) {
bool active = (searchResults[from]->_item->id == App::main()->activeMsgId());
bool selected = (from == searchedSel);
searchResults[from]->paint(p, w, active, selected);
p.translate(0, st::dlgHeight);
}
}
@ -76,7 +100,11 @@ void DialogsListWidget::paintEvent(QPaintEvent *e) {
}
void DialogsListWidget::activate() {
if ((filter.isEmpty() && !sel) || (!filter.isEmpty() && (filteredSel < 0 || filteredSel >= filtered.size()))) {
if (
(_state == DefaultState && !sel) ||
(_state == FilteredState && (filteredSel < 0 || filteredSel >= filterResults.size())) ||
(_state == SearchedState && (searchedSel < 0 || searchedSel >= searchResults.size()))
) {
selectSkip(1);
}
}
@ -93,7 +121,7 @@ void DialogsListWidget::onUpdateSelected(bool force) {
if ((!force && !rect().contains(mouse)) || !selByMouse) return;
int w = width(), mouseY = mouse.y();
if (filter.isEmpty()) {
if (_state == DefaultState) {
DialogRow *newSel = dialogs.list.rowAtY(mouseY, st::dlgHeight);
int32 otherStart = dialogs.list.count * st::dlgHeight;
if (newSel) {
@ -102,32 +130,35 @@ void DialogsListWidget::onUpdateSelected(bool force) {
newSel = contactsNoDialogs.list.rowAtY(mouseY - otherStart, st::dlgHeight);
contactSel = true;
}
if (contactSel) {
mouse.setY(mouse.y() - otherStart);
}
if (newSel) {
mouse.setY(mouse.y() - newSel->pos * st::dlgHeight);
}
if (newSel != sel) {
sel = newSel;
setCursor(sel ? style::cur_pointer : style::cur_default);
parentWidget()->update();
}
} else {
if (!filtered.isEmpty()) {
} else if (_state == FilteredState) {
if (!filterResults.isEmpty()) {
int32 newFilteredSel = mouseY / int32(st::dlgHeight);
if (newFilteredSel < 0 || newFilteredSel >= filtered.size()) {
if (newFilteredSel < 0 || newFilteredSel >= filterResults.size()) {
newFilteredSel = -1;
}
if (newFilteredSel >= 0) {
mouse.setY(mouse.y() - newFilteredSel * st::dlgHeight);
}
if (newFilteredSel != filteredSel) {
filteredSel = newFilteredSel;
setCursor((filteredSel >= 0) ? style::cur_pointer : style::cur_default);
parentWidget()->update();
}
}
} else if (_state == SearchedState) {
if (!searchResults.isEmpty()) {
int32 newSearchedSel = mouseY / int32(st::dlgHeight);
if (newSearchedSel < 0 || newSearchedSel >= searchResults.size()) {
newSearchedSel = -1;
}
if (newSearchedSel != searchedSel) {
searchedSel = newSearchedSel;
setCursor((searchedSel >= 0) ? style::cur_pointer : style::cur_default);
parentWidget()->update();
}
}
}
}
@ -141,14 +172,14 @@ void DialogsListWidget::mousePressEvent(QMouseEvent *e) {
}
void DialogsListWidget::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) {
if (!filter.isEmpty()) {
for (FilteredDialogs::iterator i = filtered.begin(), e = filtered.end(); i != e;) {
if (_state == FilteredState) {
for (FilteredDialogs::iterator i = filterResults.begin(); i != filterResults.end();) {
if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts!
if (newRow) {
*i = newRow;
++i;
} else {
i = filtered.erase(i);
i = filterResults.erase(i);
}
} else {
++i;
@ -210,11 +241,11 @@ void DialogsListWidget::removeContact(UserData *user) {
}
void DialogsListWidget::dlgUpdated(DialogRow *row) {
if (filter.isEmpty()) {
if (_state == DefaultState) {
update(0, row->pos * st::dlgHeight, width(), st::dlgHeight);
} else {
} else if (_state == FilteredState) {
int32 cnt = 0;
for (FilteredDialogs::const_iterator i = filtered.cbegin(), e = filtered.cend(); i != e; ++i) {
for (FilteredDialogs::const_iterator i = filterResults.cbegin(), e = filterResults.cend(); i != e; ++i) {
if ((*i)->history == row->history) {
update(0, cnt * st::dlgHeight, width(), st::dlgHeight);
break;
@ -225,7 +256,7 @@ void DialogsListWidget::dlgUpdated(DialogRow *row) {
}
void DialogsListWidget::dlgUpdated(History *history) {
if (filter.isEmpty()) {
if (_state == DefaultState) {
DialogRow *row = 0;
DialogsList::RowByPeer::iterator i = dialogs.list.rowByPeer.find(history->peer->id);
if (i != dialogs.list.rowByPeer.cend()) {
@ -236,15 +267,24 @@ void DialogsListWidget::dlgUpdated(History *history) {
update(0, (dialogs.list.count + i.value()->pos) * st::dlgHeight, width(), st::dlgHeight);
}
}
} else {
} else if (_state == FilteredState) {
int32 cnt = 0;
for (FilteredDialogs::const_iterator i = filtered.cbegin(), e = filtered.cend(); i != e; ++i) {
for (FilteredDialogs::const_iterator i = filterResults.cbegin(), e = filterResults.cend(); i != e; ++i) {
if ((*i)->history == history) {
update(0, cnt * st::dlgHeight, width(), st::dlgHeight);
break;
}
++cnt;
}
} else if (_state == SearchedState) {
int32 cnt = 0;
for (SearchResults::const_iterator i = searchResults.cbegin(), e = searchResults.cend(); i != e; ++i) {
if ((*i)->_item->history() == history) {
update(0, cnt * st::dlgHeight, width(), st::dlgHeight);
break;
}
++cnt;
}
}
}
@ -290,9 +330,14 @@ void DialogsListWidget::onPeerPhotoChanged(PeerData *peer) {
parentWidget()->update();
}
void DialogsListWidget::onFilterUpdate(QString newFilter) {
void DialogsListWidget::onFilterUpdate(QString newFilter, bool force) {
if (_state == SearchedState && !newFilter.trimmed().isEmpty()) {
_updateSearchTimer.start(AutoSearchTimeout);
return;
}
newFilter = textAccentFold(newFilter.trimmed().toLower());
if (newFilter != filter) {
if (newFilter != filter || force) {
QStringList f;
if (!newFilter.isEmpty()) {
QStringList filterList = newFilter.split(cWordSplit(), QString::SkipEmptyParts);
@ -306,12 +351,16 @@ void DialogsListWidget::onFilterUpdate(QString newFilter) {
}
newFilter = f.join(' ');
}
if (newFilter != filter) {
if (newFilter != filter || force) {
filter = newFilter;
if (!filter.isEmpty()) {
if (filter.isEmpty()) {
_state = DefaultState;
filterResults.clear();
} else {
QStringList::const_iterator fb = f.cbegin(), fe = f.cend(), fi;
filtered.clear();
_state = FilteredState;
filterResults.clear();
if (!f.isEmpty()) {
DialogsList *dialogsToFilter = 0, *contactsNoDialogsToFilter = 0;
if (dialogs.list.count) {
@ -338,7 +387,7 @@ void DialogsListWidget::onFilterUpdate(QString newFilter) {
}
}
}
filtered.reserve((dialogsToFilter ? dialogsToFilter->count : 0) + (contactsNoDialogsToFilter ? contactsNoDialogsToFilter->count : 0));
filterResults.reserve((dialogsToFilter ? dialogsToFilter->count : 0) + (contactsNoDialogsToFilter ? contactsNoDialogsToFilter->count : 0));
if (dialogsToFilter && dialogsToFilter->count) {
for (DialogRow *i = dialogsToFilter->begin, *e = dialogsToFilter->end; i != e; i = i->next) {
const PeerData::Names &names(i->history->peer->names);
@ -355,7 +404,7 @@ void DialogsListWidget::onFilterUpdate(QString newFilter) {
}
}
if (fi == fe) {
filtered.push_back(i);
filterResults.push_back(i);
}
}
}
@ -375,7 +424,7 @@ void DialogsListWidget::onFilterUpdate(QString newFilter) {
}
}
if (fi == fe) {
filtered.push_back(i);
filterResults.push_back(i);
}
}
}
@ -387,6 +436,41 @@ void DialogsListWidget::onFilterUpdate(QString newFilter) {
}
}
DialogsListWidget::~DialogsListWidget() {
clearSearchResults();
}
void DialogsListWidget::clearSearchResults() {
if (!searchResults.isEmpty()) {
for (SearchResults::const_iterator i = searchResults.cbegin(), e = searchResults.cend(); i != e; ++i) {
delete *i;
}
searchResults.clear();
}
}
void DialogsListWidget::onItemReplaced(HistoryItem *oldItem, HistoryItem *newItem) {
for (int i = 0; i < searchResults.size(); ++i) {
if (searchResults[i]->_item == oldItem) {
searchResults[i]->_item = newItem;
}
}
}
void DialogsListWidget::onItemRemoved(HistoryItem *item) {
int wasCount = searchResults.size();
for (int i = 0; i < searchResults.size(); ++i) {
if (searchResults[i]->_item == item) {
searchResults.remove(i);
} else {
++i;
}
}
if (wasCount != searchResults.size()) {
refresh();
}
}
void DialogsListWidget::dialogsReceived(const QVector<MTPDialog> &added) {
for (QVector<MTPDialog>::const_iterator i = added.cbegin(), e = added.cend(); i != e; ++i) {
if (i->type() == mtpc_dialog) {
@ -401,6 +485,17 @@ void DialogsListWidget::dialogsReceived(const QVector<MTPDialog> &added) {
refresh();
}
void DialogsListWidget::searchReceived(const QVector<MTPMessage> &messages, bool fromStart) {
if (fromStart) {
clearSearchResults();
}
for (QVector<MTPMessage>::const_iterator i = messages.cbegin(), e = messages.cend(); i != e; ++i) {
HistoryItem *item = App::histories().addToBack(*i, -1);
searchResults.push_back(new FakeDialogRow(item));
}
refresh();
}
void DialogsListWidget::contactsReceived(const QVector<MTPContact> &contacts) {
for (QVector<MTPContact>::const_iterator i = contacts.cbegin(), e = contacts.cend(); i != e; ++i) {
addNewContact(i->c_contact().vuser_id.v);
@ -436,7 +531,15 @@ int32 DialogsListWidget::addNewContact(int32 uid, bool select) {
}
void DialogsListWidget::refresh(bool toTop) {
resize(width(), (filter.isEmpty() ? (dialogs.list.count + contactsNoDialogs.list.count) : filtered.count()) * st::dlgHeight);
int32 cnt = 0;
if (_state == DefaultState) {
cnt = dialogs.list.count + contactsNoDialogs.list.count;
} else if (_state == FilteredState) {
cnt = filterResults.count();
} else if (_state == SearchedState) {
cnt = searchResults.count();
}
resize(width(), cnt * st::dlgHeight);
if (toTop) {
emit mustScrollTo(0, 0);
loadPeerPhotos(0);
@ -447,17 +550,37 @@ void DialogsListWidget::refresh(bool toTop) {
void DialogsListWidget::setMouseSel(bool msel, bool toTop) {
selByMouse = msel;
if (!selByMouse && toTop) {
if (filter.isEmpty()) {
if (_state == DefaultState) {
sel = (dialogs.list.count ? dialogs.list.begin : (contactsNoDialogs.list.count ? contactsNoDialogs.list.begin : 0));
contactSel = !dialogs.list.count && contactsNoDialogs.list.count;
} else {
} else if (_state == FilteredState) {
filteredSel = 0;
} else if (_state == SearchedState) {
searchedSel = -1; // don't select first elem in search
}
}
}
void DialogsListWidget::setState(State newState) {
_state = newState;
if (_state == DefaultState || _state == FilteredState) {
clearSearchResults();
searchedSel = -1;
} else if (_state == DefaultState || _state == SearchedState) {
filterResults.clear();
filteredSel = -1;
}
onFilterUpdate(filter, true);
refresh(true);
}
DialogsListWidget::State DialogsListWidget::state() const {
return _state;
}
void DialogsListWidget::clearFilter() {
if (!filter.isEmpty()) {
if (_state == FilteredState) {
_state = DefaultState;
filter = QString();
refresh(true);
}
@ -473,7 +596,7 @@ void DialogsListWidget::addDialog(const MTPDdialog &dialog) {
}
void DialogsListWidget::selectSkip(int32 direction) {
if (filter.isEmpty()) {
if (_state == DefaultState) {
if (!sel) {
if (dialogs.list.count && direction > 0) {
sel = dialogs.list.begin;
@ -499,20 +622,27 @@ void DialogsListWidget::selectSkip(int32 direction) {
}
int32 fromY = (sel->pos + (contactSel ? dialogs.list.count : 0)) * st::dlgHeight;
emit mustScrollTo(fromY, fromY + st::dlgHeight);
} else {
if (filtered.isEmpty()) return;
int32 newSel = snap(filteredSel + direction, 0, filtered.size() - 1);
} else if (_state == FilteredState) {
if (filterResults.isEmpty()) return;
int32 newSel = snap(filteredSel + direction, 0, filterResults.size() - 1);
if (newSel != filteredSel) {
filteredSel = newSel;
}
emit mustScrollTo(filteredSel * st::dlgHeight, (filteredSel + 1) * st::dlgHeight);
} else if (_state == SearchedState) {
if (searchResults.isEmpty()) return;
int32 newSel = snap(searchedSel + direction, 0, searchResults.size() - 1);
if (newSel != searchedSel) {
searchedSel = newSel;
}
emit mustScrollTo(searchedSel * st::dlgHeight, (searchedSel + 1) * st::dlgHeight);
}
parentWidget()->update();
}
void DialogsListWidget::scrollToPeer(const PeerId &peer) {
int32 fromY = -1;
if (filter.isEmpty()) {
if (_state == DefaultState) {
DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(peer);
if (i != dialogs.list.rowByPeer.cend()) {
fromY = i.value()->pos * st::dlgHeight;
@ -522,9 +652,9 @@ void DialogsListWidget::scrollToPeer(const PeerId &peer) {
fromY = (i.value()->pos + dialogs.list.count) * st::dlgHeight;
}
}
} else {
for (int32 i = 0, c = filtered.size(); i < c; ++i) {
if (filtered[i]->history->peer->id == peer) {
} else if (_state == FilteredState) {
for (int32 i = 0, c = filterResults.size(); i < c; ++i) {
if (filterResults[i]->history->peer->id == peer) {
fromY = i * st::dlgHeight;
break;
}
@ -537,7 +667,7 @@ void DialogsListWidget::scrollToPeer(const PeerId &peer) {
void DialogsListWidget::selectSkipPage(int32 pixels, int32 direction) {
int32 toSkip = pixels / int32(st::dlgHeight);
if (filter.isEmpty()) {
if (_state == DefaultState) {
if (!sel) {
if (direction > 0 && dialogs.list.count) {
sel = dialogs.list.begin;
@ -581,7 +711,7 @@ void DialogsListWidget::selectSkipPage(int32 pixels, int32 direction) {
void DialogsListWidget::loadPeerPhotos(int32 yFrom) {
int32 yTo = yFrom + parentWidget()->height() * 5;
MTP::clearLoaderPriorities();
if (filter.isEmpty()) {
if (_state == DefaultState) {
int32 otherStart = dialogs.list.count * st::dlgHeight;
if (yFrom < otherStart) {
dialogs.list.adjustCurrent(yFrom, st::dlgHeight);
@ -599,99 +729,124 @@ void DialogsListWidget::loadPeerPhotos(int32 yFrom) {
row->history->peer->photo->load();
}
}
} else {
} else if (_state == FilteredState) {
int32 from = yFrom / st::dlgHeight;
if (from < 0) from = 0;
if (from < filtered.size()) {
if (from < filterResults.size()) {
int32 to = (yTo / int32(st::dlgHeight)) + 1, w = width();
if (to > filtered.size()) to = filtered.size();
if (to > filterResults.size()) to = filterResults.size();
for (; from < to; ++from) {
filtered[from]->history->peer->photo->load();
filterResults[from]->history->peer->photo->load();
}
}
} else if (_state == SearchedState) {
int32 from = yFrom / st::dlgHeight;
if (from < 0) from = 0;
if (from < searchResults.size()) {
int32 to = (yTo / int32(st::dlgHeight)) + 1, w = width();
if (to > searchResults.size()) to = searchResults.size();
for (; from < to; ++from) {
searchResults[from]->_item->history()->peer->photo->load();
}
}
}
}
void DialogsListWidget::choosePeer() {
History *history = filter.isEmpty() ? (sel ? sel->history : 0) : ((filteredSel >= 0 && filteredSel < filtered.size()) ? filtered[filteredSel]->history : 0);
bool DialogsListWidget::choosePeer() {
History *history = 0;
MsgId msgId = 0;
if (_state == DefaultState) {
if (sel) history = sel->history;
} else if (_state == FilteredState) {
if (filteredSel >= 0 && filteredSel < filterResults.size()) history = filterResults[filteredSel]->history;
} else if (_state == SearchedState) {
if (searchedSel >= 0 && searchedSel < searchResults.size()) {
history = searchResults[searchedSel]->_item->history();
msgId = searchResults[searchedSel]->_item->id;
}
}
if (history) {
emit peerChosen(history->peer->id);
emit peerChosen(history->peer->id, msgId);
sel = 0;
filteredSel = -1;
parentWidget()->update();
return true;
}
return false;
}
void DialogsListWidget::destroyData() {
sel = 0;
contactSel = false;
filteredSel = 0;
filtered.clear();
filterResults.clear();
filter.clear();
searchedSel = 0;
clearSearchResults();
contacts.clear();
contactsNoDialogs.clear();
dialogs.clear();
}
PeerData *DialogsListWidget::peerBefore(const PeerData *peer) const {
if (!filter.isEmpty()) {
if (filtered.isEmpty() || filtered.at(0)->history->peer == peer) return 0;
if (_state == DefaultState) {
DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(peer->id);
if (i == dialogs.list.rowByPeer.constEnd()) {
i = contactsNoDialogs.list.rowByPeer.constFind(peer->id);
if (i == contactsNoDialogs.list.rowByPeer.cend()) {
return 0;
}
if (i.value()->prev) {
return i.value()->prev->history->peer;
} else if (dialogs.list.count) {
return dialogs.list.end->prev->history->peer;
}
return 0;
}
if (i.value()->prev) {
return i.value()->prev->history->peer;
}
} else if (_state == FilteredState) {
if (filterResults.isEmpty() || filterResults.at(0)->history->peer == peer) return 0;
for (FilteredDialogs::const_iterator b = filtered.cbegin(), i = b + 1, e = filtered.cend(); i != e; ++i) {
for (FilteredDialogs::const_iterator b = filterResults.cbegin(), i = b + 1, e = filterResults.cend(); i != e; ++i) {
if ((*i)->history->peer == peer) {
FilteredDialogs::const_iterator j = i - 1;
return (*j)->history->peer;
}
}
return 0;
}
DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(peer->id);
if (i == dialogs.list.rowByPeer.constEnd()) {
i = contactsNoDialogs.list.rowByPeer.constFind(peer->id);
if (i == contactsNoDialogs.list.rowByPeer.cend()) {
return 0;
}
if (i.value()->prev) {
return i.value()->prev->history->peer;
} else if (dialogs.list.count) {
return dialogs.list.end->prev->history->peer;
}
return 0;
}
if (i.value()->prev) {
return i.value()->prev->history->peer;
}
return 0;
}
PeerData *DialogsListWidget::peerAfter(const PeerData *peer) const {
if (!filter.isEmpty()) {
for (FilteredDialogs::const_iterator i = filtered.cbegin(), e = filtered.cend(); i != e; ++i) {
if (_state == DefaultState) {
DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(peer->id);
if (i == dialogs.list.rowByPeer.constEnd()) {
i = contactsNoDialogs.list.rowByPeer.constFind(peer->id);
if (i == contactsNoDialogs.list.rowByPeer.cend()) {
return 0;
}
if (i.value()->next != contactsNoDialogs.list.end) {
return i.value()->next->history->peer;
}
return 0;
}
if (i.value()->next != dialogs.list.end) {
return i.value()->next->history->peer;
} else if (contactsNoDialogs.list.count) {
return contactsNoDialogs.list.begin->history->peer;
}
} else if (_state == FilteredState) {
for (FilteredDialogs::const_iterator i = filterResults.cbegin(), e = filterResults.cend(); i != e; ++i) {
if ((*i)->history->peer == peer) {
++i;
return (i == e) ? 0 : (*i)->history->peer;
}
}
return 0;
}
DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(peer->id);
if (i == dialogs.list.rowByPeer.constEnd()) {
i = contactsNoDialogs.list.rowByPeer.constFind(peer->id);
if (i == contactsNoDialogs.list.rowByPeer.cend()) {
return 0;
}
if (i.value()->next != contactsNoDialogs.list.end) {
return i.value()->next->history->peer;
}
return 0;
}
if (i.value()->next != dialogs.list.end) {
return i.value()->next->history->peer;
} else if (contactsNoDialogs.list.count) {
return contactsNoDialogs.list.begin->history->peer;
}
return 0;
}
@ -704,6 +859,10 @@ DialogsIndexed &DialogsListWidget::dialogsList() {
return dialogs;
}
DialogsListWidget::SearchResults &DialogsListWidget::searchList() {
return searchResults;
}
DialogsWidget::DialogsWidget(MainWidget *parent) : QWidget(parent)
, _configLoaded(false)
, _drawShadow(true)
@ -712,17 +871,21 @@ DialogsWidget::DialogsWidget(MainWidget *parent) : QWidget(parent)
, dlgPreloading(0)
, contactsRequest(0)
, _filter(this, st::dlgFilter, lang(lng_dlg_filter))
, _stateSwitcher(this, st::dlgState)
, _newGroup(this, st::btnNewGroup)
, _addContact(this, st::btnAddContact)
, _cancelSearch(this, st::btnCancelSearch)
, scroll(this, st::dlgScroll)
, list(&scroll, parent)
, _searchFull(false)
{
scroll.setWidget(&list);
scroll.setFocusPolicy(Qt::NoFocus);
connect(&list, SIGNAL(mustScrollTo(int, int)), &scroll, SLOT(scrollToY(int, int)));
connect(&list, SIGNAL(dialogToTopFrom(int)), this, SLOT(onDialogToTopFrom(int)));
// connect(&list, SIGNAL(peerChosen(const PeerId &)), this, SLOT(onCancel()));
connect(&list, SIGNAL(peerChosen(const PeerId &)), this, SIGNAL(peerChosen(const PeerId &)));
// connect(&list, SIGNAL(peerChosen(const PeerId &, MsgId)), this, SLOT(onCancel()));
connect(&list, SIGNAL(peerChosen(const PeerId &, MsgId)), this, SIGNAL(peerChosen(const PeerId &, MsgId)));
connect(&list, SIGNAL(searchMessages()), this, SLOT(onSearchMessages()));
connect(&scroll, SIGNAL(geometryChanged()), &list, SLOT(onParentGeometryChanged()));
connect(&scroll, SIGNAL(scrolled()), &list, SLOT(onUpdateSelected()));
connect(&scroll, SIGNAL(scrolled()), this, SLOT(onListScroll()));
@ -731,17 +894,26 @@ DialogsWidget::DialogsWidget(MainWidget *parent) : QWidget(parent)
connect(parent, SIGNAL(dialogsUpdated()), this, SLOT(onListScroll()));
connect(&_addContact, SIGNAL(clicked()), this, SLOT(onAddContact()));
connect(&_newGroup, SIGNAL(clicked()), this, SLOT(onNewGroup()));
connect(&_cancelSearch, SIGNAL(clicked()), this, SLOT(onCancelSearch()));
_stateSwitcher.addButton(lang(lng_dlg_conversations));
_stateSwitcher.addButton(lang(lng_dlg_messages));
_stateSwitcher.hide();
connect(&_stateSwitcher, SIGNAL(changed()), this, SLOT(onStateChange()));
scroll.show();
_filter.show();
_filter.move(st::dlgPaddingHor, st::dlgFilterPadding);
_stateSwitcher.move(st::dlgPaddingHor, st::dlgFilterPadding * 2 + _filter.height());
_filter.setFocusPolicy(Qt::StrongFocus);
_filter.customUpDown(true);
_addContact.hide();
_newGroup.show();
_cancelSearch.hide();
_newGroup.move(width() - _newGroup.width() - st::dlgPaddingHor, 0);
_addContact.move(width() - _addContact.width() - st::dlgPaddingHor, 0);
scroll.move(0, _filter.height() + 2 * st::dlgFilterPadding);
_cancelSearch.move(width() - _cancelSearch.width() - st::dlgPaddingHor, 0);
}
void DialogsWidget::activate() {
@ -804,12 +976,16 @@ bool DialogsWidget::animStep(float64) {
}
void DialogsWidget::onCancel() {
list.clearFilter();
_filter.clear();
_filter.updatePlaceholder();
onCancelSearch();
emit cancelled();
}
void DialogsWidget::clearFiltered() {
if (list.state() != DialogsListWidget::SearchedState) {
onCancel();
}
}
void DialogsWidget::unreadCountsReceived(const QVector<MTPDialog> &dialogs) {
for (QVector<MTPDialog>::const_iterator i = dialogs.cbegin(), e = dialogs.cend(); i != e; ++i) {
const MTPDdialog &d(i->c_dialog());
@ -875,6 +1051,32 @@ bool DialogsWidget::dialogsFailed(const RPCError &e) {
return true;
}
void DialogsWidget::onSearchMessages(bool force) {
QString q = _filter.text().trimmed();
if (q.isEmpty()) {
if (_searchRequest) {
MTP::cancel(_searchRequest);
_searchRequest = 0;
}
if (force) {
list.setState(DialogsListWidget::DefaultState);
}
return;
}
if (force || _searchQuery != q) {
if (_searchRequest) MTP::cancel(_searchRequest);
_searchQuery = q;
_searchFull = false;
_searchRequest = MTP::send(MTPmessages_Search(MTP_inputPeerEmpty(), MTP_string(_searchQuery), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, true), rpcFail(&DialogsWidget::searchFailed));
}
}
void DialogsWidget::onSearchMore(MsgId minMsgId) {
if (!_searchRequest && !_searchFull) {
_searchRequest = MTP::send(MTPmessages_Search(MTP_inputPeerEmpty(), MTP_string(_searchQuery), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(minMsgId), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, !minMsgId), rpcFail(&DialogsWidget::searchFailed));
}
}
void DialogsWidget::loadConfig() {
if (!_configLoaded) {
mtpConfigLoader()->load();
@ -905,6 +1107,41 @@ bool DialogsWidget::contactsFailed() {
return true;
}
void DialogsWidget::searchReceived(bool fromStart, const MTPmessages_Messages &result, mtpRequestId req) {
if (_searchRequest == req) {
switch (result.type()) {
case mtpc_messages_messages: {
App::feedUsers(result.c_messages_messages().vusers);
App::feedChats(result.c_messages_messages().vchats);
const QVector<MTPMessage> &msgs(result.c_messages_messages().vmessages.c_vector().v);
list.searchReceived(msgs, fromStart);
if (msgs.isEmpty()) {
_searchFull = true;
}
} break;
case mtpc_messages_messagesSlice: {
App::feedUsers(result.c_messages_messagesSlice().vusers);
App::feedChats(result.c_messages_messagesSlice().vchats);
const QVector<MTPMessage> &msgs(result.c_messages_messagesSlice().vmessages.c_vector().v);
list.searchReceived(msgs, fromStart);
if (msgs.isEmpty()) {
_searchFull = true;
}
} break;
}
_searchRequest = 0;
}
}
bool DialogsWidget::searchFailed(const RPCError &error, mtpRequestId req) {
if (_searchRequest == req) {
_searchRequest = 0;
_searchFull = true;
}
return true;
}
bool DialogsWidget::addNewContact(int32 uid, bool show) {
_filter.setText(QString());
onFilterUpdate();
@ -917,21 +1154,53 @@ bool DialogsWidget::addNewContact(int32 uid, bool show) {
void DialogsWidget::onListScroll() {
list.loadPeerPhotos(scroll.scrollTop());
if (scroll.scrollTop() > list.dialogsList().list.count * st::dlgHeight - scroll.height()) {
if (list.state() == DialogsListWidget::SearchedState) {
DialogsListWidget::SearchResults &res(list.searchList());
if (scroll.scrollTop() > res.size() * st::dlgHeight - 2 * scroll.height()) {
onSearchMore(res.isEmpty() ? 0 : res.back()->_item->id);
}
} else if (scroll.scrollTop() > list.dialogsList().list.count * st::dlgHeight - scroll.height()) {
loadDialogs();
}
}
void DialogsWidget::onFilterUpdate() {
list.onFilterUpdate(_filter.text());
QString filterText = _filter.text();
list.onFilterUpdate(filterText);
DialogsListWidget::State s = list.state();
bool switcherVisible = (s != DialogsListWidget::DefaultState);
if (switcherVisible && _stateSwitcher.isHidden() || !switcherVisible && !_stateSwitcher.isHidden()) {
if (switcherVisible) {
_stateSwitcher.show();
} else {
_stateSwitcher.hide();
_stateSwitcher.setSelected(0);
}
resizeEvent(0);
}
if (filterText.isEmpty() && !_cancelSearch.isHidden()) {
_cancelSearch.hide();
_newGroup.show();
} else if (!filterText.isEmpty() && _cancelSearch.isHidden()) {
_cancelSearch.show();
_newGroup.hide();
}
}
void DialogsWidget::resizeEvent(QResizeEvent *e) {
int32 w = width() - st::dlgShadow;
_filter.setGeometry(st::dlgPaddingHor, st::dlgFilterPadding, w - 2 * st::dlgPaddingHor, _filter.height());
_stateSwitcher.setGeometry(st::dlgPaddingHor, st::dlgFilterPadding * 2 + _filter.height(), _filter.width(), _filter.height());
_newGroup.move(w - _newGroup.width() - st::dlgPaddingHor, _filter.y());
_addContact.move(w - _addContact.width() - st::dlgPaddingHor, _filter.y());
scroll.resize(w, height() - _filter.y() - _filter.height() - st::dlgFilterPadding - st::dlgPaddingVer);
_cancelSearch.move(w - _cancelSearch.width() - st::dlgPaddingHor, _filter.y());
if (_stateSwitcher.isHidden()) {
scroll.move(0, _filter.height() + 2 * st::dlgFilterPadding);
scroll.resize(w, height() - _filter.y() - _filter.height() - st::dlgFilterPadding - st::dlgPaddingVer);
} else {
scroll.move(0, _filter.height() + _stateSwitcher.height() + 3 * st::dlgFilterPadding);
scroll.resize(w, height() - _stateSwitcher.y() - _stateSwitcher.height() - st::dlgFilterPadding - st::dlgPaddingVer);
}
list.resize(w, list.height());
onListScroll();
}
@ -940,7 +1209,9 @@ void DialogsWidget::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Escape) {
e->ignore();
} else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
list.choosePeer();
if (!list.choosePeer() && list.state() == DialogsListWidget::SearchedState) {
onSearchMessages();
}
} else if (e->key() == Qt::Key_Down) {
list.setMouseSel(false);
list.selectSkip(1);
@ -981,7 +1252,9 @@ PeerData *DialogsWidget::peerAfter(const PeerData *peer) const {
}
void DialogsWidget::scrollToPeer(const PeerId &peer) {
list.scrollToPeer(peer);
if (list.state() != DialogsListWidget::SearchedState) {
list.scrollToPeer(peer);
}
}
void DialogsWidget::removePeer(PeerData *peer) {
@ -1008,6 +1281,32 @@ void DialogsWidget::onNewGroup() {
App::wnd()->showLayer(new NewGroupBox());
}
void DialogsWidget::onCancelSearch() {
list.clearFilter();
_filter.clear();
_filter.updatePlaceholder();
onFilterUpdate();
}
void DialogsWidget::onStateChange() {
if (!_stateSwitcher.isHidden()) {
if (_stateSwitcher.selected() == 0) {
list.setState(DialogsListWidget::FilteredState);
_searchQuery = QString();
if (_searchRequest) {
MTP::cancel(_searchRequest);
_searchRequest = 0;
}
} else {
list.setState(DialogsListWidget::SearchedState);
}
list.onFilterUpdate(_filter.text());
if (list.state() == DialogsListWidget::SearchedState) {
onSearchMessages(true);
}
}
}
void DialogsWidget::onDialogToTopFrom(int movedFrom) {
if (scroll.scrollTop() > 0) {
if (movedFrom > scroll.scrollTop()) {

View File

@ -27,6 +27,7 @@ public:
DialogsListWidget(QWidget *parent, MainWidget *main);
void dialogsReceived(const QVector<MTPDialog> &dialogs);
void searchReceived(const QVector<MTPMessage> &messages, bool fromStart);
void showMore(int32 pixels);
void activate();
@ -53,7 +54,7 @@ public:
void clearFilter();
void refresh(bool toTop = false);
void choosePeer();
bool choosePeer();
void destroyData();
@ -61,11 +62,26 @@ public:
PeerData *peerAfter(const PeerData *peer) const;
void scrollToPeer(const PeerId &peer);
typedef QVector<FakeDialogRow*> SearchResults;
DialogsIndexed &contactsList();
DialogsIndexed &dialogsList();
SearchResults &searchList();
void setMouseSel(bool msel, bool toTop = false);
enum State {
DefaultState = 0,
FilteredState = 1,
SearchedState = 2,
};
void setState(State newState);
State state() const;
void onFilterUpdate(QString newFilter, bool force = false);
~DialogsListWidget();
public slots:
void onUpdateSelected(bool force = false);
@ -74,17 +90,21 @@ public slots:
void onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
void onPeerPhotoChanged(PeerData *peer);
void onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow);
void onFilterUpdate(QString newFilter);
void onItemRemoved(HistoryItem *item);
void onItemReplaced(HistoryItem *oldItem, HistoryItem *newItem);
signals:
void peerChosen(const PeerId &);
void peerChosen(const PeerId &, MsgId);
void mustScrollTo(int scrollToTop, int scrollToBottom);
void dialogToTopFrom(int movedFrom);
void searchMessages();
private:
void addDialog(const MTPDdialog &dialog);
void clearSearchResults();
DialogsIndexed dialogs;
DialogsIndexed contactsNoDialogs;
@ -95,9 +115,17 @@ private:
QString filter;
typedef QVector<DialogRow*> FilteredDialogs;
FilteredDialogs filtered;
FilteredDialogs filterResults;
int32 filteredSel;
SearchResults searchResults;
int32 searchedSel;
State _state;
QTimer _updateSearchTimer;
QString _searchQuery;
QPoint lastMousePos;
void paintDialog(QPainter &p, DialogRow *dialog);
@ -112,6 +140,7 @@ public:
void dialogsReceived(const MTPmessages_Dialogs &dialogs);
void contactsReceived(const MTPcontacts_Contacts &contacts);
void searchReceived(bool fromStart, const MTPmessages_Messages &result, mtpRequestId req);
bool addNewContact(int32 uid, bool show = true);
void resizeEvent(QResizeEvent *e);
@ -143,10 +172,13 @@ public:
DialogsIndexed &contactsList();
void enableShadow(bool enable = true);
void onSearchMore(MsgId minMsgId);
void clearFiltered();
signals:
void peerChosen(const PeerId &);
void peerChosen(const PeerId &, MsgId);
void cancelled();
public slots:
@ -157,8 +189,12 @@ public slots:
void onFilterUpdate();
void onAddContact();
void onNewGroup();
void onCancelSearch();
void onStateChange();
void onDialogToTopFrom(int movedFrom);
void onSearchMessages(bool force = false);
private:
@ -169,15 +205,21 @@ private:
void unreadCountsReceived(const QVector<MTPDialog> &dialogs);
bool dialogsFailed(const RPCError &e);
bool contactsFailed();
bool searchFailed(const RPCError &error, mtpRequestId req);
int32 dlgOffset, dlgCount;
mtpRequestId dlgPreloading;
mtpRequestId contactsRequest;
FlatInput _filter;
IconedButton _newGroup, _addContact;
Switcher _stateSwitcher;
IconedButton _newGroup, _addContact, _cancelSearch;
ScrollArea scroll;
DialogsListWidget list;
QString _searchQuery;
bool _searchFull;
mtpRequestId _searchRequest;
};

View File

@ -115,6 +115,9 @@ void FileUploader::sendNext() {
}
} else {
toSend = i->media.data.mid(i->docSentParts * i->docPartSize, i->docPartSize);
if (i->media.type == ToPrepareDocument && i->docSentParts <= UseBigFilesFrom) {
i->docHash.feed(toSend.constData(), toSend.size());
}
}
if (toSend.size() > i->docPartSize || (toSend.size() < i->docPartSize && i->docSentParts + 1 != i->docPartsCount)) {
currentFailed();

View File

@ -224,7 +224,7 @@ public:
}
} else {
if (!objs.size()) {
timer.start(7);
timer.start(AnimationTimerDelta);
}
objs.insert(obj);
}

View File

@ -0,0 +1,157 @@
/*
This file is part of Telegram Desktop,
an unofficial desktop 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.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014 John Preston, https://tdesktop.com
*/
#include "stdafx.h"
#include "switcher.h"
Switcher::Switcher(QWidget *parent, const style::switcher &st) : TWidget(parent)
, _selected(0)
, _over(-1)
, _wasOver(-1)
, _pressed(-1)
, _st(st)
, a_bgOver(_st.bgColor->c)
, a_bgWasOver(_st.bgHovered->c) {
resize(width(), _st.height);
}
void Switcher::leaveEvent(QEvent *e) {
setOver(-1);
if (_pressed >= 0) return;
setMouseTracking(false);
return TWidget::leaveEvent(e);
}
void Switcher::enterEvent(QEvent *e) {
setMouseTracking(true);
return TWidget::enterEvent(e);
}
void Switcher::mousePressEvent(QMouseEvent *e) {
if (e->buttons() & Qt::LeftButton) {
mouseMoveEvent(e);
if (_over != _pressed) {
_pressed = _over;
e->accept();
}
}
}
void Switcher::mouseMoveEvent(QMouseEvent *e) {
if (rect().contains(e->pos())) {
if (width()) {
setOver((e->pos().x() * _buttons.size()) / width());
}
} else {
setOver(-1);
}
}
void Switcher::mouseReleaseEvent(QMouseEvent *e) {
if (_pressed >= 0) {
if (_pressed == _over && _pressed != _selected) {
setSelected(_pressed);
} else {
setSelected(_selected);
}
} else {
leaveEvent(e);
}
}
void Switcher::addButton(const QString &btn) {
_buttons.push_back(btn);
update();
}
bool Switcher::animStep(float64 ms) {
float64 dt = ms / _st.duration;
bool res = true;
if (dt >= 1) {
res = false;
a_bgOver.finish();
a_bgWasOver.finish();
} else {
a_bgOver.update(dt, anim::linear);
a_bgWasOver.update(dt, anim::linear);
}
update();
return res;
}
void Switcher::paintEvent(QPaintEvent *e) {
QPainter p(this);
p.fillRect(rect(), _st.bgColor->b);
if (!_buttons.isEmpty()) {
p.setFont(_st.font->f);
float64 btnWidth = float64(width()) / _buttons.size();
for (int i = 0; i < _buttons.size(); ++i) {
QRect btnRect(qRound(i * btnWidth), 0, qRound((i + 1) * btnWidth) - qRound(i * btnWidth), height());
if (i == _selected) {
p.fillRect(btnRect, _st.bgActive->b);
} else if (i == _over) {
p.fillRect(btnRect, a_bgOver.current());
} else if (i == _wasOver) {
p.fillRect(btnRect, a_bgWasOver.current());
}
p.setPen((i == _selected ? _st.activeColor : _st.textColor)->p);
p.drawText(btnRect, _buttons[i], style::al_center);
}
}
if (_st.border) {
p.setPen(_st.borderColor->p);
for (uint32 i = 0; i < _st.border; ++i) {
p.drawRect(i, i, width() - 2 * i - 1, height() - 2 * i - 1);
}
}
}
int Switcher::selected() const {
return _selected;
}
void Switcher::setSelected(int selected) {
if (selected != _selected) {
_selected = selected;
emit changed();
}
_pressed = _over = _wasOver = -1;
anim::stop(this);
setCursor(style::cur_default);
update();
}
void Switcher::setOver(int over) {
if (over != _over) {
QColor c(a_bgOver.current());
if (_wasOver == over) {
a_bgOver = anim::cvalue(a_bgWasOver.current(), _st.bgHovered->c);
} else {
a_bgOver = anim::cvalue(_st.bgColor->c, _st.bgHovered->c);
}
a_bgWasOver = anim::cvalue(c, _st.bgColor->c);
_wasOver = _over;
_over = over;
anim::start(this);
setCursor((_over >= 0 && _over != _selected) ? style::cur_pointer : style::cur_default);
}
}

View File

@ -0,0 +1,62 @@
/*
This file is part of Telegram Desktop,
an unofficial desktop 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.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014 John Preston, https://tdesktop.com
*/
#pragma once
#include <QtWidgets/QWidget>
#include "gui/twidget.h"
class Switcher : public TWidget, public Animated {
Q_OBJECT
public:
Switcher(QWidget *parent, const style::switcher &st);
void mousePressEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void paintEvent(QPaintEvent *e);
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
void addButton(const QString &btn);
bool animStep(float64 ms);
int selected() const;
void setSelected(int selected);
signals:
void changed();
private:
void setOver(int over);
int _selected;
int _over, _wasOver, _pressed;
typedef QVector<QString> Buttons;
Buttons _buttons;
style::switcher _st;
anim::cvalue a_bgOver, a_bgWasOver;
};

View File

@ -499,7 +499,8 @@ void DialogRow::paint(QPainter &p, int32 w, bool act, bool sel) const {
rectForName.setLeft(rectForName.left() + st::dlgChatImgSkip);
}
if (history->isEmpty()) {
HistoryItem *last = history->last;
if (!last) {
p.setFont(st::dlgHistFont->f);
p.setPen((act ? st::dlgActiveColor : st::dlgSystemColor)->p);
if (history->typing.isEmpty()) {
@ -509,7 +510,6 @@ void DialogRow::paint(QPainter &p, int32 w, bool act, bool sel) const {
}
} else {
// draw date
HistoryItem *last = history->back()->back();
QDateTime now(QDateTime::currentDateTime()), lastTime(last->date);
QDate nowDate(now.date()), lastDate(lastTime.date());
QString dt;
@ -571,17 +571,77 @@ void DialogRow::paint(QPainter &p, int32 w, bool act, bool sel) const {
history->nameText.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
}
void FakeDialogRow::paint(QPainter &p, int32 w, bool act, bool sel) const {
QRect fullRect(0, 0, w, st::dlgHeight);
p.fillRect(fullRect, (act ? st::dlgActiveBG : (sel ? st::dlgHoverBG : st::dlgBG))->b);
History *history = _item->history();
p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, history->peer->photo->pix(st::dlgPhotoSize));
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->chat) {
p.drawPixmap(QPoint(rectForName.left() + st::dlgChatImgLeft, rectForName.top() + st::dlgChatImgTop), App::sprite(), (act ? st::dlgActiveChatImg : st::dlgChatImg));
rectForName.setLeft(rectForName.left() + st::dlgChatImgSkip);
}
// draw date
QDateTime now(QDateTime::currentDateTime()), lastTime(_item->date);
QDate nowDate(now.date()), lastDate(lastTime.date());
QString dt;
if (lastDate == nowDate) {
dt = lastTime.toString(qsl("hh:mm"));
} 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->m.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->out() && _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, unread = history->unreadCount;
_item->drawInDialog(p, QRect(nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, lastWidth, st::dlgFont->height), act, _cacheFor, _cache);
p.setPen((act ? st::dlgActiveColor : st::dlgNameColor)->p);
history->nameText.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
}
History::History(const PeerId &peerId) : width(0), height(0)
, msgCount(0)
, offset(0)
, unreadCount(0)
, inboxReadTill(0)
, outboxReadTill(0)
, showFrom(0)
, notifyFrom(0)
, unreadBar(0)
, unreadLoaded(true)
, peer(App::peer(peerId))
, oldLoaded(false)
, newLoaded(true)
, last(0)
, activeMsgId(0)
, lastWidth(0)
, lastScrollTop(History::ScrollMax)
, mute(isNotifyMuted(peer->notify))
@ -746,7 +806,7 @@ Histories::Parent::iterator Histories::erase(Histories::Parent::iterator i) {
return Parent::erase(i);
}
PeerId Histories::addToBack(const MTPmessage &msg, bool newMsg) {
HistoryItem *Histories::addToBack(const MTPmessage &msg, int msgState) {
PeerId from_id = 0, to_id = 0;
switch (msg.type()) {
case mtpc_message:
@ -770,11 +830,24 @@ PeerId Histories::addToBack(const MTPmessage &msg, bool newMsg) {
if (h == end()) {
h = insert(peer, new History(peer));
}
h.value()->addToBack(msg, newMsg);
return peer;
if (msgState < 0) {
return h.value()->addToHistory(msg);
}
if (!h.value()->loadedAtBottom()) {
HistoryItem *item = h.value()->addToHistory(msg);
if (item) {
h.value()->last = item;
if (msgState > 0) {
h.value()->newItemAdded(item);
}
}
return item;
}
return h.value()->addToBack(msg, msgState > 0);
}
/*
PeerId Histories::addToBack(const MTPgeoChatMessage &msg, bool newMsg) {
HistoryItem *Histories::addToBack(const MTPgeoChatMessage &msg, bool newMsg) {
PeerId peer = 0;
switch (msg.type()) {
case mtpc_geoChatMessage:
@ -790,11 +863,10 @@ PeerId Histories::addToBack(const MTPgeoChatMessage &msg, bool newMsg) {
if (h == end()) {
h = insert(peer, new History(peer));
}
h.value()->addToBack(msg, newMsg);
return peer;
return h.value()->addToBack(msg, newMsg);
}/**/
HistoryItem *History::createItem(HistoryBlock *block, const MTPmessage &msg, bool newMsg) {
HistoryItem *History::createItem(HistoryBlock *block, const MTPmessage &msg, bool newMsg, bool returnExisting) {
HistoryItem *result = 0;
switch (msg.type()) {
@ -870,7 +942,7 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPmessage &msg, boo
} break;
}
return regItem(result);
return regItem(result, returnExisting);
}
HistoryItem *History::createItemForwarded(HistoryBlock *block, MsgId id, HistoryMessage *msg) {
@ -902,7 +974,7 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPgeoChatMessage &m
return regItem(result);
}
/**/
void History::addToBackService(MsgId msgId, QDateTime date, const QString &text, bool out, bool unread, HistoryMedia *media, bool newMsg) {
HistoryItem *History::addToBackService(MsgId msgId, QDateTime date, const QString &text, bool out, bool unread, HistoryMedia *media, bool newMsg) {
HistoryBlock *to = 0;
bool newBlock = isEmpty();
if (newBlock) {
@ -911,10 +983,10 @@ void History::addToBackService(MsgId msgId, QDateTime date, const QString &text,
to = back();
}
doAddToBack(to, newBlock, regItem(new HistoryServiceMsg(this, to, msgId, date, text, out, unread, media)), newMsg);
return doAddToBack(to, newBlock, regItem(new HistoryServiceMsg(this, to, msgId, date, text, out, unread, media)), newMsg);
}
void History::addToBack(const MTPmessage &msg, bool newMsg) {
HistoryItem *History::addToBack(const MTPmessage &msg, bool newMsg) {
HistoryBlock *to = 0;
bool newBlock = isEmpty();
if (newBlock) {
@ -922,10 +994,14 @@ void History::addToBack(const MTPmessage &msg, bool newMsg) {
} else {
to = back();
}
doAddToBack(to, newBlock, createItem(to, msg, newMsg), newMsg);
return doAddToBack(to, newBlock, createItem(to, msg, newMsg), newMsg);
}
void History::addToBackForwarded(MsgId id, HistoryMessage *item) {
HistoryItem *History::addToHistory(const MTPmessage &msg) {
return createItem(0, msg, false, true);
}
HistoryItem *History::addToBackForwarded(MsgId id, HistoryMessage *item) {
HistoryBlock *to = 0;
bool newBlock = isEmpty();
if (newBlock) {
@ -933,11 +1009,11 @@ void History::addToBackForwarded(MsgId id, HistoryMessage *item) {
} else {
to = back();
}
doAddToBack(to, newBlock, createItemForwarded(to, id, item), true);
return doAddToBack(to, newBlock, createItemForwarded(to, id, item), true);
}
/*
void History::addToBack(const MTPgeoChatMessage &msg, bool newMsg) {
HistoryItem *History::addToBack(const MTPgeoChatMessage &msg, bool newMsg) {
HistoryBlock *to = 0;
bool newBlock = isEmpty();
if (newBlock) {
@ -946,7 +1022,7 @@ void History::addToBack(const MTPgeoChatMessage &msg, bool newMsg) {
to = back();
}
doAddToBack(to, newBlock, createItem(to, msg, newMsg), newMsg);
return doAddToBack(to, newBlock, createItem(to, msg, newMsg), newMsg);
}
/**/
@ -965,10 +1041,10 @@ void History::createInitialDateBlock(const QDateTime &date) {
push_front(dateBlock); // date block
}
void History::doAddToBack(HistoryBlock *to, bool newBlock, HistoryItem *adding, bool newMsg) {
HistoryItem *History::doAddToBack(HistoryBlock *to, bool newBlock, HistoryItem *adding, bool newMsg) {
if (!adding) {
if (newBlock) delete to;
return;
return adding;
}
if (newBlock) {
@ -987,6 +1063,7 @@ void History::doAddToBack(HistoryBlock *to, bool newBlock, HistoryItem *adding,
}
}
to->push_back(adding);
last = adding;
adding->y = to->height;
if (width) {
int32 dh = adding->resize(width);
@ -994,37 +1071,42 @@ void History::doAddToBack(HistoryBlock *to, bool newBlock, HistoryItem *adding,
height += dh;
}
setMsgCount(msgCount + 1);
if (adding->id > 0) {
++offset;
}
if (newMsg) {
App::checkImageCacheSize();
if (adding->from()) {
TypingUsers::iterator i = typing.find(adding->from());
if (i != typing.end()) {
uint64 ms = getms();
i.value() = ms;
updateTyping(ms, 0, true);
App::main()->topBar()->update();
}
}
if (adding->out()) {
inboxRead(false);
if (unreadBar) unreadBar->destroy();
} else if (adding->unread()) {
if (!notifyFrom) notifyFrom = adding;
App::main()->newUnreadMsg(this, adding->id);
}
if (dialogs.isEmpty()) {
App::main()->createDialogAtTop(this, unreadCount);
} else {
emit App::main()->dialogToTop(dialogs);
newItemAdded(adding);
}
return adding;
}
void History::newItemAdded(HistoryItem *item) {
App::checkImageCacheSize();
if (item->from()) {
TypingUsers::iterator i = typing.find(item->from());
if (i != typing.end()) {
uint64 ms = getms();
i.value() = ms;
updateTyping(ms, 0, true);
App::main()->topBar()->update();
}
}
if (item->out()) {
inboxRead(false);
if (unreadBar) unreadBar->destroy();
} else if (item->unread()) {
notifies.push_back(item);
App::main()->newUnreadMsg(this, item->id);
}
if (dialogs.isEmpty()) {
App::main()->createDialogAtTop(this, unreadCount);
} else {
emit App::main()->dialogToTop(dialogs);
}
}
void History::addToFront(const QVector<MTPMessage> &slice) {
if (slice.isEmpty()) return;
if (slice.isEmpty()) {
oldLoaded = true;
return;
}
int32 addToH = 0, skip = 0;
if (!isEmpty()) {
@ -1049,9 +1131,6 @@ void History::addToFront(const QVector<MTPMessage> &slice) {
adding->y = block->height;
block->height += adding->resize(width);
setMsgCount(msgCount + 1);
if (adding->id > 0) {
++offset;
}
prev = adding;
}
if (i == e) break;
@ -1063,7 +1142,7 @@ void History::addToFront(const QVector<MTPMessage> &slice) {
block->height += dayItem->resize(width);
}
if (block->size()) {
if (wasMsgCount < unreadCount && msgCount >= unreadCount) {
if (wasMsgCount < unreadCount && msgCount >= unreadCount && !activeMsgId) {
for (int32 i = block->size(); i > 0; --i) {
if ((*block)[i - 1]->itemType() == HistoryItem::MsgType) {
++wasMsgCount;
@ -1105,9 +1184,66 @@ void History::addToFront(const QVector<MTPMessage> &slice) {
}
}
void History::addToBack(const QVector<MTPMessage> &slice) {
if (slice.isEmpty()) {
newLoaded = true;
return;
}
bool wasEmpty = isEmpty();
HistoryItem *prev = isEmpty() ? 0 : back()->back();
HistoryBlock *block = new HistoryBlock(this);
block->reserve(slice.size());
int32 wasMsgCount = msgCount;
for (QVector<MTPmessage>::const_iterator i = slice.cend(), e = slice.cbegin(); i != e;) {
--i;
HistoryItem *adding = createItem(block, *i, false);
if (adding) {
if (prev && prev->date.date() != adding->date.date()) {
HistoryItem *dayItem = createDayServiceMsg(this, block, adding->date);
prev->block()->push_back(dayItem);
dayItem->y = prev->block()->height;
prev->block()->height += dayItem->resize(width);
if (prev->block() != block) {
height += dayItem->height();
}
}
block->push_back(adding);
adding->y = block->height;
block->height += adding->resize(width);
setMsgCount(msgCount + 1);
prev = adding;
}
if (i == e) break;
}
if (block->size()) {
block->y = height;
push_back(block);
height += block->height;
} else {
newLoaded = true;
fixLastMessage(true);
delete block;
}
if (wasEmpty && !isEmpty()) {
HistoryBlock *dateBlock = new HistoryBlock(this);
HistoryItem *dayItem = createDayServiceMsg(this, dateBlock, front()->front()->date);
dateBlock->push_back(dayItem);
int32 dh = dayItem->resize(width);
dateBlock->height = dh;
for (iterator i = begin(), e = end(); i != e; ++i) {
(*i)->y += dh;
}
push_front(dateBlock); // date block
height += dh;
}
}
void History::inboxRead(bool byThisInstance) {
if (unreadCount) {
if (!byThisInstance) App::main()->historyToDown(this);
if (!byThisInstance && loadedAtBottom()) App::main()->historyToDown(this);
setUnreadCount(0);
}
if (!isEmpty()) {
@ -1118,7 +1254,7 @@ void History::inboxRead(bool byThisInstance) {
if (App::main()) App::main()->dlgUpdated(dialogs[0]);
}
App::wnd()->psClearNotify(this);
clearNotifyFrom();
clearNotifications();
}
void History::outboxRead() {
@ -1130,7 +1266,7 @@ void History::outboxRead() {
void History::setUnreadCount(int32 newUnreadCount, bool psUpdate) {
if (unreadCount != newUnreadCount) {
if (!unreadCount && newUnreadCount == 1) {
if (!unreadCount && newUnreadCount == 1 && loadedAtBottom()) {
showFrom = isEmpty() ? 0 : back()->back();
} else if (!newUnreadCount) {
showFrom = 0;
@ -1138,7 +1274,6 @@ void History::setUnreadCount(int32 newUnreadCount, bool psUpdate) {
App::histories().unreadFull += newUnreadCount - unreadCount;
if (mute) App::histories().unreadMuted += newUnreadCount - unreadCount;
unreadCount = newUnreadCount;
unreadLoaded = (unreadCount <= msgCount);
if (psUpdate) App::wnd()->psUpdateCounter();
if (unreadBar) unreadBar->setCount(unreadCount);
}
@ -1147,7 +1282,6 @@ void History::setUnreadCount(int32 newUnreadCount, bool psUpdate) {
void History::setMsgCount(int32 newMsgCount) {
if (msgCount != newMsgCount) {
msgCount = newMsgCount;
unreadLoaded = (unreadCount <= msgCount);
}
}
@ -1160,6 +1294,10 @@ void History::setMsgCount(int32 newMsgCount) {
}
void History::getNextShowFrom(HistoryBlock *block, int32 i) {
if (!loadedAtBottom()) {
showFrom = 0;
return;
}
if (i >= 0) {
int32 l = block->size();
for (++i; i < l; ++i) {
@ -1186,7 +1324,7 @@ void History::getNextShowFrom(HistoryBlock *block, int32 i) {
}
void History::addUnreadBar() {
if (unreadBar || !showFrom || !unreadCount) return;
if (unreadBar || !showFrom || !unreadCount || !loadedAtBottom()) return;
HistoryBlock *block = showFrom->block();
int32 i = block->indexOf(showFrom);
@ -1210,41 +1348,77 @@ void History::addUnreadBar() {
height += dh;
}
void History::getNextNotifyFrom(HistoryBlock *block, int32 i) {
if (!block) {
if (!notifyFrom) {
return;
}
block = notifyFrom->block();
i = block->indexOf(notifyFrom);
}
if (i >= 0) {
int32 l = block->size();
for (++i; i < l; ++i) {
if ((*block)[i]->unread() && !(*block)[i]->out()) {
notifyFrom = (*block)[i];
return;
}
}
}
int32 j = indexOf(block), s = size();
if (j >= 0) {
for (++j; j < s; ++j) {
block = (*this)[j];
for (int32 i = 0, l = block->size(); i < l; ++i) {
if ((*block)[i]->unread() && !(*block)[i]->out()) {
notifyFrom = (*block)[i];
return;
}
}
}
}
notifyFrom = 0;
void History::clearNotifications() {
notifies.clear();
}
void History::clearNotifyFrom() {
notifyFrom = 0;
bool History::readyForWork() const {
return activeMsgId ? !isEmpty() : (unreadCount <= msgCount);
}
bool History::loadedAtBottom() const {
return newLoaded;
}
bool History::loadedAtTop() const {
return oldLoaded;
}
void History::fixLastMessage(bool wasAtBottom) {
if (wasAtBottom && isEmpty()) {
wasAtBottom = false;
}
if (wasAtBottom) {
last = back()->back();
} else {
last = 0;
if (App::main()) {
App::main()->checkPeerHistory(peer);
}
}
}
void History::loadAround(MsgId msgId) {
if (activeMsgId != msgId) {
activeMsgId = msgId;
lastWidth = 0;
if (activeMsgId) {
HistoryItem *item = App::histItemById(activeMsgId);
if (!item || !item->block()) {
clear(true);
}
newLoaded = last && !last->detached();
} else {
if (!loadedAtBottom()) {
clear(true);
}
newLoaded = isEmpty() || last && !last->detached();
}
}
}
MsgId History::minMsgId() const {
for (const_iterator i = cbegin(), e = cend(); i != e; ++i) {
for (HistoryBlock::const_iterator j = (*i)->cbegin(), en = (*i)->cend(); j != en; ++j) {
if ((*j)->id > 0) {
return (*j)->id;
}
}
}
return 0;
}
MsgId History::maxMsgId() const {
for (const_iterator i = cend(), e = cbegin(); i != e;) {
--i;
for (HistoryBlock::const_iterator j = (*i)->cend(), en = (*i)->cbegin(); j != en;) {
--j;
if ((*j)->id > 0) {
return (*j)->id;
}
}
}
return 0;
}
int32 History::geomResize(int32 newWidth, int32 *ytransform) {
@ -1269,13 +1443,26 @@ int32 History::geomResize(int32 newWidth, int32 *ytransform) {
return height;
}
void History::clear() {
void History::clear(bool leaveItems) {
if (unreadBar) {
unreadBar->destroy();
}
if (showFrom) {
showFrom = 0;
}
for (Parent::const_iterator i = cbegin(), e = cend(); i != e; ++i) {
if (leaveItems) {
(*i)->clear(true);
}
delete *i;
}
Parent::clear();
setUnreadCount(0);
setMsgCount(0);
if (!leaveItems) {
setUnreadCount(0);
}
height = 0;
oldLoaded = false;
}
History::Parent::iterator History::erase(History::Parent::iterator i) {
@ -1328,12 +1515,19 @@ int32 HistoryBlock::geomResize(int32 newWidth, int32 *ytransform) {
return height;
}
void HistoryBlock::clear() {
for (Parent::const_iterator i = cbegin(), e = cend(); i != e; ++i) {
delete *i;
void HistoryBlock::clear(bool leaveItems) {
if (leaveItems) {
for (Parent::const_iterator i = cbegin(), e = cend(); i != e; ++i) {
(*i)->detachFast();
}
} else {
for (Parent::const_iterator i = cbegin(), e = cend(); i != e; ++i) {
delete *i;
}
}
Parent::clear();
}
HistoryBlock::Parent::iterator HistoryBlock::erase(HistoryBlock::Parent::iterator i) {
delete *i;
return Parent::erase(i);
@ -1341,9 +1535,6 @@ HistoryBlock::Parent::iterator HistoryBlock::erase(HistoryBlock::Parent::iterato
void HistoryBlock::removeItem(HistoryItem *item) {
int32 i = indexOf(item), dh = 0;
if (history->notifyFrom == item) {
history->getNextNotifyFrom(this, i);
}
if (history->showFrom == item) {
history->getNextShowFrom(this, i);
}
@ -1406,9 +1597,6 @@ void HistoryBlock::removeItem(HistoryItem *item) {
if (!item->out() && item->unread() && history->unreadCount) {
history->setUnreadCount(history->unreadCount - 1);
}
if (item->id > 0) {
--history->offset;
}
int32 itemType = item->itemType();
if (itemType == HistoryItem::MsgType) {
history->setMsgCount(history->msgCount - 1);
@ -1430,10 +1618,6 @@ void HistoryBlock::removeItem(HistoryItem *item) {
} else {
history->removeBlock(this);
}
delete item;
if (h->unreadBar && h->back()->back() == h->unreadBar) {
h->unreadBar->destroy();
}
}
HistoryItem::HistoryItem(History *history, HistoryBlock *block, MsgId msgId, bool out, bool unread, QDateTime msgDate, int32 from) : y(0)
@ -1460,6 +1644,28 @@ void HistoryItem::markRead() {
}
}
void HistoryItem::detach() {
if (_history && _history->unreadBar == this) {
_history->unreadBar = 0;
}
if (_block) {
_block->removeItem(this);
detachFast();
App::historyItemDetached(this);
} else {
if (_history->showFrom == this) {
_history->showFrom = 0;
}
}
if (_history && _history->unreadBar && _history->back()->back() == _history->unreadBar) {
_history->unreadBar->destroy();
}
}
void HistoryItem::detachFast() {
_block = 0;
}
HistoryItem::~HistoryItem() {
App::historyUnregItem(this);
if (id < 0) {
@ -1467,12 +1673,14 @@ HistoryItem::~HistoryItem() {
}
}
HistoryItem *regItem(HistoryItem *item) {
if (item && App::historyRegItem(item)) {
return item;
HistoryItem *regItem(HistoryItem *item, bool returnExisting) {
if (!item) return 0;
HistoryItem *existing = App::historyRegItem(item);
if (existing) {
delete item;
return returnExisting ? existing : 0;
}
delete item;
return 0;
return item;
}
HistoryPhoto::HistoryPhoto(const MTPDphoto &photo, int32 width) : data(App::feedPhoto(photo))
@ -2497,6 +2705,21 @@ HistoryMedia *HistoryMessage::getMedia() const {
void HistoryMessage::draw(QPainter &p, uint32 selection) const {
textstyleSet(&(out() ? st::outTextStyle : st::inTextStyle));
if (id == _history->activeMsgId) {
uint64 ms = App::main() ? App::main()->animActiveTime() : 0;
if (ms) {
if (ms > st::activeFadeInDuration + st::activeFadeOutDuration) {
App::main()->stopAnimActive();
} else {
float64 dt = (ms > st::activeFadeInDuration) ? (1 - (ms - st::activeFadeInDuration) / float64(st::activeFadeOutDuration)) : (ms / float64(st::activeFadeInDuration));
float64 o = p.opacity();
p.setOpacity(o * dt);
p.fillRect(0, 0, _history->width, _height, textstyleCurrent()->selectOverlay->b);
p.setOpacity(o);
}
}
}
bool selected = (selection == FullItemSel);
if (_from->nameVersion > _fromVersion) {
fromNameUpdated();

View File

@ -527,8 +527,8 @@ struct Histories : public QHash<PeerId, History*> {
unreadFull = unreadMuted = 0;
}
PeerId addToBack(const MTPmessage &msg, bool newMsg = true);
// PeerId addToBack(const MTPgeoChatMessage &msg, bool newMsg = true);
HistoryItem *addToBack(const MTPmessage &msg, int msgState = 1); // 1 - new message, 0 - not new message, -1 - searched message
// HistoryItem *addToBack(const MTPgeoChatMessage &msg, bool newMsg = true);
typedef QMap<History*, uint64> TypingHistories; // when typing in this history started
TypingHistories typing;
@ -551,6 +551,17 @@ struct DialogRow {
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(QPainter &p, int32 w, bool act, bool sel) const;
HistoryItem *_item;
mutable const HistoryItem *_cacheFor;
mutable Text _cache;
};
class HistoryMedia;
class HistoryMessage;
class HistoryUnreadBar;
@ -558,7 +569,7 @@ struct History : public QList<HistoryBlock*> {
History(const PeerId &peerId);
typedef QList<HistoryBlock*> Parent;
void clear();
void clear(bool leaveItems = false);
Parent::iterator erase(Parent::iterator i);
void blockResized(HistoryBlock *block, int32 dh);
void removeBlock(HistoryBlock *block);
@ -567,16 +578,21 @@ struct History : public QList<HistoryBlock*> {
clear();
}
HistoryItem *createItem(HistoryBlock *block, const MTPmessage &msg, bool newMsg);
HistoryItem *createItem(HistoryBlock *block, const MTPmessage &msg, bool newMsg, bool returnExisting = false);
HistoryItem *createItemForwarded(HistoryBlock *block, MsgId id, HistoryMessage *msg);
// HistoryItem *createItem(HistoryBlock *block, const MTPgeoChatMessage &msg, bool newMsg);
void addToBackService(MsgId msgId, QDateTime date, const QString &text, bool out = false, bool unread = false, HistoryMedia *media = 0, bool newMsg = true);
void addToBack(const MTPmessage &msg, bool newMsg = true);
void addToBackForwarded(MsgId id, HistoryMessage *item);
// void addToBack(const MTPgeoChatMessage &msg, bool newMsg = true);
HistoryItem *addToBackService(MsgId msgId, QDateTime date, const QString &text, bool out = false, bool unread = false, HistoryMedia *media = 0, bool newMsg = true);
HistoryItem *addToBack(const MTPmessage &msg, bool newMsg = true);
HistoryItem *addToHistory(const MTPmessage &msg);
HistoryItem *addToBackForwarded(MsgId id, HistoryMessage *item);
// HistoryItem *addToBack(const MTPgeoChatMessage &msg, bool newMsg = true);
void addToFront(const QVector<MTPMessage> &slice);
void addToBack(const QVector<MTPMessage> &slice);
void createInitialDateBlock(const QDateTime &date);
void doAddToBack(HistoryBlock *to, bool newBlock, HistoryItem *adding, bool newMsg);
HistoryItem *doAddToBack(HistoryBlock *to, bool newBlock, HistoryItem *adding, bool newMsg);
void newItemAdded(HistoryItem *item);
void inboxRead(bool byThisInstance = false);
void outboxRead();
@ -585,18 +601,66 @@ struct History : public QList<HistoryBlock*> {
void setMute(bool newMute);
void getNextShowFrom(HistoryBlock *block, int32 i);
void addUnreadBar();
void getNextNotifyFrom(HistoryBlock *block = 0, int32 i = 0);
void clearNotifyFrom();
void clearNotifications();
bool readyForWork() const; // all unread loaded or loaded around activeMsgId
bool loadedAtBottom() const; // last message is in the list
bool loadedAtTop() const; // nothing was added after loading history back
void fixLastMessage(bool wasAtBottom);
void loadAround(MsgId msgId);
MsgId minMsgId() const;
MsgId maxMsgId() const;
int32 geomResize(int32 newWidth, int32 *ytransform = 0); // return new size
int32 width, height, msgCount, offset, unreadCount;
int32 width, height, msgCount, unreadCount;
int32 inboxReadTill, outboxReadTill;
HistoryItem *showFrom;
HistoryItem *notifyFrom;
HistoryUnreadBar *unreadBar;
bool unreadLoaded;
PeerData *peer;
bool oldLoaded, newLoaded;
HistoryItem *last;
MsgId activeMsgId;
typedef QList<HistoryItem*> NotifyQueue;
NotifyQueue notifies;
void removeNotification(HistoryItem *item) {
if (!notifies.isEmpty()) {
for (NotifyQueue::iterator i = notifies.begin(), e = notifies.end(); i != e; ++i) {
if ((*i) == item) {
notifies.erase(i);
break;
}
}
}
}
HistoryItem *currentNotification() {
return notifies.isEmpty() ? 0 : notifies.front();
}
void skipNotification() {
if (!notifies.isEmpty()) {
notifies.pop_front();
}
}
void itemReplaced(HistoryItem *old, HistoryItem *item) {
if (!notifies.isEmpty()) {
for (NotifyQueue::iterator i = notifies.begin(), e = notifies.end(); i != e; ++i) {
if ((*i) == old) {
*i = item;
break;
}
}
}
if (last == old) {
last = item;
}
// showFrom can't be detached
}
QString draft;
QTextCursor draftCur;
@ -911,7 +975,7 @@ struct HistoryBlock : public QVector<HistoryItem*> {
}
typedef QVector<HistoryItem*> Parent;
void clear();
void clear(bool leaveItems = false);
Parent::iterator erase(Parent::iterator i);
~HistoryBlock() {
clear();
@ -979,7 +1043,18 @@ public:
}
void destroy() {
markRead();
_block->removeItem(this);
bool wasAtBottom = history()->loadedAtBottom();
_history->removeNotification(this);
detach();
if (history()->last == this) {
history()->fixLastMessage(wasAtBottom);
}
delete this;
}
void detach();
void detachFast();
bool detached() const {
return !_block;
}
bool out() const {
return _out;
@ -1047,7 +1122,7 @@ protected:
};
HistoryItem *regItem(HistoryItem *item);
HistoryItem *regItem(HistoryItem *item, bool returnExisting = false);
enum HistoryMediaType {
MediaTypePhoto,

View File

@ -72,8 +72,12 @@ void HistoryList::messagesReceived(const QVector<MTPMessage> &messages) {
hist->addToFront(messages);
}
void HistoryList::messagesReceivedDown(const QVector<MTPMessage> &messages) {
hist->addToBack(messages);
}
void HistoryList::updateMsg(HistoryItem *msg) {
if (!msg || !hist || hist != msg->history()) return;
if (!msg || msg->detached() || !hist || hist != msg->history()) return;
update(0, height() - hist->height - st::historyPadding + msg->block()->y + msg->y, width(), msg->height());
}
@ -331,7 +335,7 @@ void HistoryList::touchScrollUpdated(const QPoint &screenPos) {
}
QPoint HistoryList::mapMouseToItem(QPoint p, HistoryItem *item) {
if (!item) return QPoint(0, 0);
if (!item || item->detached()) return QPoint(0, 0);
p.setY(p.y() - (height() - hist->height - st::historyPadding) - item->block()->y - item->y);
return p;
}
@ -550,13 +554,22 @@ void HistoryList::mouseReleaseEvent(QMouseEvent *e) {
}
void HistoryList::mouseDoubleClickEvent(QMouseEvent *e) {
if (_dragAction == Selecting && _dragSelType == TextSelectLetters && _dragItem && !_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) {
if ((_dragAction == Selecting && !_selected.isEmpty() && _selected.cbegin().value() != FullItemSel || _dragAction == NoDrag && (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel)) && _dragSelType == TextSelectLetters && _dragItem) {
bool afterDragSymbol, uponSelected;
uint16 symbol;
_dragItem->getSymbol(symbol, afterDragSymbol, uponSelected, _dragStartPos.x(), _dragStartPos.y());
if (uponSelected) {
_dragSymbol = symbol;
_dragSelType = TextSelectWords;
if (_dragAction == NoDrag) {
_dragAction = Selecting;
uint32 selStatus = (symbol << 16) | symbol;
if (!_selected.isEmpty()) {
updateMsg(_selected.cbegin().key());
_selected.clear();
}
_selected.insert(_dragItem, selStatus);
}
mouseMoveEvent(e);
_trippleClickPoint = e->globalPos();
@ -1436,17 +1449,15 @@ HistoryHider::~HistoryHider() {
}
HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
, histOffset(0)
, histCount(-1)
, histReadRequestId(0)
, histRequestsCount(0)
, histPeer(0)
, _activePeer(0)
, _activeHist(0)
, histPreloading(0)
, _scroll(this, st::historyScroll, false)
, _list(0)
, hist(0)
, _histInited(false)
, _toHistoryEnd(this, st::historyToEnd)
, _send(this, lang(lng_send_button), st::btnSend)
, _attachDocument(this, st::btnAttachDocument)
, _attachPhoto(this, st::btnAttachPhoto)
@ -1472,6 +1483,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
setAcceptDrops(true);
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onListScroll()));
connect(&_toHistoryEnd, SIGNAL(clicked()), this, SLOT(onHistoryToEnd()));
connect(&_send, SIGNAL(clicked()), this, SLOT(onSend()));
connect(&_attachDocument, SIGNAL(clicked()), this, SLOT(onDocumentSelect()));
connect(&_attachPhoto, SIGNAL(clicked()), this, SLOT(onPhotoSelect()));
@ -1489,8 +1501,14 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
_scrollTimer.setSingleShot(false);
_animActiveTimer.setSingleShot(false);
connect(&_animActiveTimer, SIGNAL(timeout()), this, SLOT(onAnimActiveStep()));
_scroll.hide();
_scroll.move(0, 0);
_toHistoryEnd.hide();
_field.hide();
_field.resize(width() - _send.width() - _attachDocument.width() - _attachEmoji.width(), _send.height() - 2 * st::sendPadding);
_send.hide();
@ -1509,6 +1527,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
_emojiPan.hide();
_attachDragDocument.hide();
_attachDragPhoto.hide();
connect(&_attachDragDocument, SIGNAL(dropped(QDropEvent*)), this, SLOT(onDocumentDrop(QDropEvent*)));
connect(&_attachDragPhoto, SIGNAL(dropped(QDropEvent*)), this, SLOT(onPhotoDrop(QDropEvent*)));
}
@ -1565,7 +1584,7 @@ void HistoryWidget::chatLoaded(const MTPmessages_ChatFull &res) {
peerUpdated(App::chat(peerId));
}
void HistoryWidget::showPeer(const PeerId &peer, bool force, bool leaveActive) {
void HistoryWidget::showPeer(const PeerId &peer, MsgId msgId, bool force, bool leaveActive) {
if (App::main()->selectingPeer() && !force) {
hiderOffered = true;
App::main()->offerPeer(peer);
@ -1577,19 +1596,31 @@ void HistoryWidget::showPeer(const PeerId &peer, bool force, bool leaveActive) {
if (hist) {
if (histPeer->id == peer) {
if (hist->unreadBar) hist->unreadBar->destroy();
if (msgId != hist->activeMsgId) {
hist->loadAround(msgId);
if (histPreloading) MTP::cancel(histPreloading);
if (histPreloadingDown) MTP::cancel(histPreloadingDown);
histPreloading = histPreloadingDown = 0;
}
checkUnreadLoaded();
return activate();
}
updateTyping(false);
}
if (histPreload.size() && _list) {
_list->messagesReceived(histPreload);
histPreload.clear();
if (_list) {
if (!histPreload.isEmpty()) {
_list->messagesReceived(histPreload);
histPreload.clear();
}
if (!histPreloadDown.isEmpty()) {
_list->messagesReceivedDown(histPreloadDown);
histPreloadDown.clear();
}
}
if (hist) {
hist->draft = _field.getText();
hist->draftCur = _field.textCursor();
if (hist->unreadLoaded && _scroll.scrollTop() + 1 <= _scroll.scrollTopMax()) {
if (hist->readyForWork() && _scroll.scrollTop() + 1 <= _scroll.scrollTopMax()) {
hist->lastWidth = _list->width();
} else {
hist->lastWidth = 0;
@ -1603,26 +1634,25 @@ void HistoryWidget::showPeer(const PeerId &peer, bool force, bool leaveActive) {
_list = 0;
updateTopBarSelection();
if (leaveActive && histPeer) {
_activePeer = histPeer;
if (leaveActive && hist) {
_activeHist = hist;
} else {
if (!leaveActive) {
_activePeer = 0;
_activeHist = 0;
}
if (hist) {
App::main()->dlgUpdated(hist);
}
}
histPeer = peer ? App::peer(peer) : 0;
histOffset = 0;
histReadRequestId = 0;
titlePeerText = QString();
titlePeerTextWidth = 0;
histRequestsCount = 0;
histCount = -1;
histPreload.clear();
histPreloadDown.clear();
if (histPreloading) MTP::cancel(histPreloading);
histPreloading = 0;
if (histPreloadingDown) MTP::cancel(histPreloadingDown);
histPreloading = histPreloadingDown = 0;
hist = 0;
_histInited = false;
noSelectingScroll();
@ -1653,14 +1683,15 @@ void HistoryWidget::showPeer(const PeerId &peer, bool force, bool leaveActive) {
} else {
hist = i.value();
}
if (hist->unreadLoaded) {
if (hist->readyForWork()) {
_scroll.show();
}
if (hist) {
App::main()->dlgUpdated(hist);
}
histOffset = hist->offset;
_list = new HistoryList(this, &_scroll, hist);
hist->loadAround(msgId);
_list->hide();
_scroll.setWidget(_list);
_list->show();
@ -1689,7 +1720,7 @@ void HistoryWidget::showPeer(const PeerId &peer, bool force, bool leaveActive) {
void HistoryWidget::checkUnreadLoaded(bool checkOnlyShow) {
if (!hist) return;
if (hist->unreadLoaded) {
if (hist->readyForWork()) {
if (checkOnlyShow && !_scroll.isHidden()) return;
if (!animating()) {
if (_scroll.isHidden()) {
@ -1702,7 +1733,7 @@ void HistoryWidget::checkUnreadLoaded(bool checkOnlyShow) {
}
updateListSize(0, true);
if (!animating()) updateControlsVisibility();
if (hist->unreadLoaded) {
if (hist->readyForWork()) {
if (!_scroll.isHidden() && !_list->isHidden()) {
onListScroll();
}
@ -1715,6 +1746,7 @@ void HistoryWidget::updateControlsVisibility() {
if (!hist) {
_scroll.hide();
_send.hide();
_toHistoryEnd.hide();
_field.hide();
_attachDocument.hide();
_attachPhoto.hide();
@ -1724,7 +1756,12 @@ void HistoryWidget::updateControlsVisibility() {
return;
}
if (hist->unreadLoaded) {
if (hist->readyForWork()) {
if (hist->loadedAtBottom()) {
_toHistoryEnd.hide();
} else {
_toHistoryEnd.show();
}
if (!histPeer->chat || !histPeer->asChat()->forbidden) {
_send.show();
if (cDefaultAttach() == dbidaPhoto) {
@ -1735,6 +1772,7 @@ void HistoryWidget::updateControlsVisibility() {
_attachEmoji.show();
if (_field.isHidden()) {
_field.show();
resizeEvent(0);
update();
}
} else {
@ -1746,15 +1784,17 @@ void HistoryWidget::updateControlsVisibility() {
_emojiPan.hide();
if (!_field.isHidden()) {
_field.hide();
resizeEvent(0);
update();
}
}
if (hist->unreadCount && App::wnd()->historyIsActive()) {
historyWasRead();
}
} else {
loadMessages();
if (!hist->unreadLoaded) {
if (!hist->readyForWork()) {
_scroll.hide();
_send.hide();
_attachDocument.hide();
@ -1762,6 +1802,7 @@ void HistoryWidget::updateControlsVisibility() {
_attachEmoji.hide();
_attachType.hide();
_emojiPan.hide();
_toHistoryEnd.hide();
if (!_field.isHidden()) {
_field.hide();
update();
@ -1772,7 +1813,7 @@ void HistoryWidget::updateControlsVisibility() {
void HistoryWidget::newUnreadMsg(History *history, MsgId msgId) {
if (App::wnd()->historyIsActive()) {
if (hist == history && hist->unreadLoaded) {
if (hist == history && hist->readyForWork()) {
historyWasRead();
if (_scroll.scrollTop() + 1 > _scroll.scrollTopMax()) {
if (history->unreadBar) history->unreadBar->destroy();
@ -1784,7 +1825,7 @@ void HistoryWidget::newUnreadMsg(History *history, MsgId msgId) {
history->setUnreadCount(history->unreadCount + 1);
}
} else {
if (hist == history && hist->unreadLoaded) {
if (hist == history && hist->readyForWork()) {
if (_scroll.scrollTop() + 1 > _scroll.scrollTopMax()) {
if (history->unreadBar) history->unreadBar->destroy();
}
@ -1810,15 +1851,17 @@ bool HistoryWidget::messagesFailed(const RPCError &e, mtpRequestId requestId) {
LOG(("RPC Error: %1 %2: %3").arg(e.code()).arg(e.type()).arg(e.description()));
if (histPreloading == requestId) {
histPreloading = 0;
} else if (histPreloadingDown == requestId) {
histPreloadingDown = 0;
}
return true;
}
void HistoryWidget::messagesReceived(const MTPmessages_Messages &messages, mtpRequestId requestId) {
if (histPreloading == requestId) {
histPreloading = 0;
if (!hist) {
histPreloading = histPreloadingDown = 0;
return;
}
if (!hist) return;
PeerId peer = 0;
int32 count = 0;
@ -1859,36 +1902,64 @@ void HistoryWidget::messagesReceived(const MTPmessages_Messages &messages, mtpRe
peer = (to_id == App::peerFromUser(MTP::authedId())) ? from_id : to_id;
}
bool down = false;
if (histPreloading == requestId) {
histPreloading = 0;
} else if (histPreloadingDown == requestId) {
histPreloadingDown = 0;
down = true;
} else {
return;
}
if (peer && peer != histPeer->id) return;
if (histList) {
if (!histOffset) {
addMessagesToFront(*histList);
if (!hist->minMsgId() || histList->isEmpty()) {
if (down) {
addMessagesToBack(*histList);
histPreloadDown.clear();
} else {
addMessagesToFront(*histList);
histPreload.clear();
}
} else {
histPreload = *histList;
}
if (histList->size()) {
histOffset += histList->size();
histCount = count;
} else {
histCount = histOffset;
if (down) {
histPreloadDown = *histList;
} else {
histPreload = *histList;
}
}
} else {
histCount = histOffset;
if (!hist->unreadLoaded) {
hist->setUnreadCount(hist->msgCount);
if (down) {
addMessagesToBack(QVector<MTPMessage>());
} else {
addMessagesToFront(QVector<MTPMessage>());
}
if (!hist->readyForWork()) {
if (hist->activeMsgId) {
hist->activeMsgId = 0;
}
if (!hist->readyForWork()) {
hist->setUnreadCount(hist->msgCount);
}
}
checkUnreadLoaded(true);
return;
}
if (histOffset >= histCount && histPreload.size()) {
if (down && hist->loadedAtBottom() && histPreloadDown.size()) {
addMessagesToBack(histPreloadDown);
histPreloadDown.clear();
loadMessagesDown();
} else if (!down && hist->loadedAtTop() && histPreload.size()) {
addMessagesToFront(histPreload);
histPreload.clear();
loadMessages();
} else if (histPreload.size()) {
} else if (down && histPreloadDown.size() || !down && histPreload.size()) {
onListScroll();
} else if (down) {
loadMessagesDown();
} else {
loadMessages();
}
@ -1901,11 +1972,20 @@ void HistoryWidget::windowShown() {
resizeEvent(0);
}
bool HistoryWidget::isActive() const {
return !hist || hist->loadedAtBottom();
}
void HistoryWidget::loadMessages() {
if (!hist) return;
if (histCount >= 0 && histOffset >= histCount) {
if (!hist->unreadLoaded) {
hist->setUnreadCount(hist->msgCount);
if (hist->loadedAtTop()) {
if (!hist->readyForWork()) {
if (hist->activeMsgId) {
hist->activeMsgId = 0;
}
if (!hist->readyForWork()) {
hist->setUnreadCount(hist->msgCount);
}
}
checkUnreadLoaded(true);
return;
@ -1913,19 +1993,53 @@ void HistoryWidget::loadMessages() {
int32 dh = 0;
if (histPreload.size()) {
bool unreadLoaded = hist->unreadLoaded;
bool loaded = hist->readyForWork();
addMessagesToFront(histPreload);
histPreload.clear();
checkUnreadLoaded(true);
if (!unreadLoaded && hist->unreadLoaded) {
if (!loaded && hist->readyForWork()) {
return;
}
}
if (!histPreloading && (!hist->unreadLoaded || _scroll.scrollTop() < 3 * _scroll.height())) {
int32 loadCount = histOffset ? MessagesPerPage : MessagesFirstLoad;
histPreloading = MTP::send(MTPmessages_GetHistory(histInputPeer, MTP_int(histOffset), MTP_int(0), MTP_int(loadCount)), rpcDone(&HistoryWidget::messagesReceived), rpcFail(&HistoryWidget::messagesFailed));
if (!histPreloading && (!hist->readyForWork() || _scroll.scrollTop() < 3 * _scroll.height())) {
MsgId min = hist->minMsgId();
int32 offset = 0, loadCount = min ? MessagesPerPage : MessagesFirstLoad;
if (!min && hist->activeMsgId) {
min = hist->activeMsgId;
offset = -loadCount / 2;
}
histPreloading = MTP::send(MTPmessages_GetHistory(histInputPeer, MTP_int(offset), MTP_int(min), MTP_int(loadCount)), rpcDone(&HistoryWidget::messagesReceived), rpcFail(&HistoryWidget::messagesFailed));
++histRequestsCount;
if (!hist->unreadLoaded) update();
if (!hist->readyForWork()) update();
} else {
checkUnreadLoaded(true);
}
}
void HistoryWidget::loadMessagesDown() {
if (!hist) return;
if (hist->loadedAtBottom()) {
return;
}
int32 dh = 0;
if (histPreloadDown.size()) {
bool loaded = hist->readyForWork();
addMessagesToBack(histPreloadDown);
histPreloadDown.clear();
checkUnreadLoaded(true);
if (!loaded && hist->readyForWork()) {
return;
}
}
if (!histPreloadingDown && hist->readyForWork() && (_scroll.scrollTop() + 3 * _scroll.height() > _scroll.scrollTopMax())) {
MsgId max = hist->maxMsgId();
if (max) {
int32 loadCount = MessagesPerPage, offset = -loadCount;
histPreloadingDown = MTP::send(MTPmessages_GetHistory(histInputPeer, MTP_int(offset), MTP_int(max + 1), MTP_int(loadCount)), rpcDone(&HistoryWidget::messagesReceived), rpcFail(&HistoryWidget::messagesFailed));
++histRequestsCount;
if (!hist->readyForWork()) update();
}
} else {
checkUnreadLoaded(true);
}
@ -1934,12 +2048,16 @@ void HistoryWidget::loadMessages() {
void HistoryWidget::onListScroll() {
App::checkImageCacheSize();
if (histPreloading || !hist || ((_list->isHidden() || _scroll.isHidden() || !App::wnd()->windowHandle()->isVisible()) && hist->unreadLoaded)) {
if (histPreloading || !hist || ((_list->isHidden() || _scroll.isHidden() || !App::wnd()->windowHandle()->isVisible()) && hist->readyForWork())) {
checkUnreadLoaded(true);
return;
}
if (!hist->unreadLoaded || _scroll.scrollTop() < 3 * _scroll.height()) {
if (hist->readyForWork() && (_scroll.scrollTop() + 3 * _scroll.height() > _scroll.scrollTopMax())) {
loadMessagesDown();
}
if (!hist->readyForWork() || _scroll.scrollTop() < 3 * _scroll.height()) {
loadMessages();
} else {
checkUnreadLoaded(true);
@ -1961,6 +2079,13 @@ QString HistoryWidget::prepareMessage(QString result) {
return (cReplaceEmojis() ? replaceEmojis(result) : result).trimmed();
}
void HistoryWidget::onHistoryToEnd() {
_toHistoryEnd.hide();
if (hist && !hist->loadedAtBottom()) {
showPeer(histPeer->id, 0);
}
}
void HistoryWidget::onSend() {
if (!hist) return;
@ -1971,6 +2096,8 @@ void HistoryWidget::onSend() {
App::historyRegRandom(randomId, newId);
hist->loadAround(0);
MTPstring msgText(MTP_string(text));
hist->addToBack(MTP_message(MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(histPeer->id), MTP_bool(true), MTP_bool(true), MTP_int(unixtime()), msgText, MTP_messageMediaEmpty()));
App::main()->historyToDown(hist);
@ -1997,7 +2124,7 @@ mtpRequestId HistoryWidget::onForward(const PeerId &peer, bool forwardSelected)
if (toForward.isEmpty()) return 0;
if (toForward.size() == 1) {
App::main()->showPeer(peer, false, true);
App::main()->showPeer(peer, 0, false, true);
if (!hist) return 0;
HistoryItem *item = toForward.cbegin().value();
@ -2006,6 +2133,7 @@ mtpRequestId HistoryWidget::onForward(const PeerId &peer, bool forwardSelected)
HistoryServiceMsg *srv = dynamic_cast<HistoryServiceMsg*>(item);
MsgId newId = 0;
hist->loadAround(0);
if (item->id > 0 && msg) {
newId = clientMsgId();
hist->addToBackForwarded(newId, msg);
@ -2045,12 +2173,14 @@ mtpRequestId HistoryWidget::onForward(const PeerId &peer, bool forwardSelected)
void HistoryWidget::onShareContact(const PeerId &peer, UserData *contact) {
if (!contact || contact->phone.isEmpty()) return;
App::main()->showPeer(peer, false, true);
App::main()->showPeer(peer, 0, false, true);
if (!hist) return;
uint64 randomId = MTP::nonce<uint64>();
MsgId newId = clientMsgId();
hist->loadAround(0);
hist->addToBack(MTP_message(MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(histPeer->id), MTP_bool(true), MTP_bool(true), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaContact(MTP_string(contact->phone), MTP_string(contact->firstName), MTP_string(contact->lastName), MTP_int(int32(contact->id & 0xFFFFFFFF)))));
MTP::send(MTPmessages_SendMedia(histPeer->input, MTP_inputMediaContact(MTP_string(contact->phone), MTP_string(contact->firstName), MTP_string(contact->lastName)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId));
@ -2066,7 +2196,11 @@ PeerData *HistoryWidget::peer() const {
}
PeerData *HistoryWidget::activePeer() const {
return histPeer ? histPeer : _activePeer;
return histPeer ? histPeer : (_activeHist ? _activeHist->peer : 0);
}
MsgId HistoryWidget::activeMsgId() const {
return hist ? hist->activeMsgId : (_activeHist ? _activeHist->activeMsgId : 0);
}
void HistoryWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back) {
@ -2077,6 +2211,7 @@ void HistoryWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTo
_animTopBarCache = myGrab(App::main()->topBar(), QRect(0, 0, width(), st::topBarHeight));
App::main()->topBar()->startAnim();
_scroll.hide();
_toHistoryEnd.hide();
_attachDocument.hide();
_attachPhoto.hide();
_attachEmoji.hide();
@ -2103,7 +2238,7 @@ bool HistoryWidget::animStep(float64 ms) {
_bgAnimCache = _animCache = _animTopBarCache = _bgAnimTopBarCache = QPixmap();
App::main()->topBar()->stopAnim();
updateControlsVisibility();
if (hist && hist->unreadLoaded) {
if (hist && hist->readyForWork()) {
_scroll.show();
if (hist->lastScrollTop == History::ScrollMax) {
_scroll.scrollToY(hist->lastScrollTop);
@ -2197,18 +2332,24 @@ void HistoryWidget::dragEnterEvent(QDragEnterEvent *e) {
}
void HistoryWidget::dragLeaveEvent(QDragLeaveEvent *e) {
_attachDrag = DragStateNone;
updateDragAreas();
if (_attachDrag != DragStateNone || !_attachDragPhoto.isHidden() || !_attachDragDocument.isHidden()) {
_attachDrag = DragStateNone;
updateDragAreas();
}
}
void HistoryWidget::leaveEvent(QEvent *e) {
_attachDrag = DragStateNone;
updateDragAreas();
if (_attachDrag != DragStateNone || !_attachDragPhoto.isHidden() || !_attachDragDocument.isHidden()) {
_attachDrag = DragStateNone;
updateDragAreas();
}
}
void HistoryWidget::mouseReleaseEvent(QMouseEvent *e) {
_attachDrag = DragStateNone;
updateDragAreas();
if (_attachDrag != DragStateNone || !_attachDragPhoto.isHidden() || !_attachDragDocument.isHidden()) {
_attachDrag = DragStateNone;
updateDragAreas();
}
}
DragState HistoryWidget::getDragState(const QMimeData *d) {
@ -2486,13 +2627,18 @@ void HistoryWidget::confirmSendImage(const ReadyLocalMedia &img) {
App::uploader()->uploadMedia(newId, img);
History *h = App::history(img.peer);
if (img.type == ToPreparePhoto) {
App::history(img.peer)->addToBack(MTP_message(MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(img.peer), MTP_bool(true), MTP_bool(true), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(img.photo)));
h->loadAround(0);
h->addToBack(MTP_message(MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(img.peer), MTP_bool(true), MTP_bool(true), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(img.photo)));
} else if (img.type == ToPrepareDocument) {
App::history(img.peer)->addToBack(MTP_message(MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(img.peer), MTP_bool(true), MTP_bool(true), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(img.document)));
h->loadAround(0);
h->addToBack(MTP_message(MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(img.peer), MTP_bool(true), MTP_bool(true), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(img.document)));
}
if (hist && histPeer && img.peer == histPeer->id) App::main()->historyToDown(hist);
if (hist && histPeer && img.peer == histPeer->id) {
App::main()->historyToDown(hist);
}
App::main()->dialogsToUp();
peerMessagesUpdated(img.peer);
}
@ -2580,6 +2726,9 @@ void HistoryWidget::resizeEvent(QResizeEvent *e) {
updateListSize();
_field.resize(width() - _send.width() - _attachDocument.width() - _attachEmoji.width(), _field.height());
_toHistoryEnd.move((width() - _toHistoryEnd.width()) / 2, _scroll.y() + _scroll.height() - _toHistoryEnd.height() - st::historyToEndSkip);
_attachEmoji.move(_field.x() + _field.width(), height() - _attachEmoji.height());
_send.move(width() - _send.width(), _attachDocument.y());
@ -2604,15 +2753,16 @@ void HistoryWidget::resizeEvent(QResizeEvent *e) {
}
}
void HistoryWidget::updateListSize(int32 addToY, bool initial) {
void HistoryWidget::updateListSize(int32 addToY, bool initial, bool loadedDown) {
if (!hist || (!_histInited && !initial)) return;
if (!App::wnd()->isVisible()) return; // scrollTopMax etc are not working after recountHeight()
int32 newScrollHeight = height() - (hist->unreadLoaded && (!histPeer->chat || !histPeer->asChat()->forbidden) ? (_field.height() + 2 * st::sendPadding) : 0);
int32 newScrollHeight = height() - (hist->readyForWork() && (!histPeer->chat || !histPeer->asChat()->forbidden) ? (_field.height() + 2 * st::sendPadding) : 0);
bool wasAtBottom = _scroll.scrollTop() + 1 > _scroll.scrollTopMax(), needResize = _scroll.width() != width() || _scroll.height() != newScrollHeight;
if (needResize) {
_scroll.resize(width(), newScrollHeight);
_toHistoryEnd.move((width() - _toHistoryEnd.width()) / 2, _scroll.y() + _scroll.height() - _toHistoryEnd.height() - st::historyToEndSkip);
}
if (!initial) {
@ -2627,20 +2777,29 @@ void HistoryWidget::updateListSize(int32 addToY, bool initial) {
if (washidden) {
_scroll.hide();
}
if (!hist->unreadLoaded) return;
if (!hist->readyForWork()) return;
if (!initial && !wasAtBottom) {
if (!initial && !wasAtBottom || loadedDown) {
_scroll.scrollToY(newSt + addToY);
return;
}
if (!hist->unreadLoaded) return;
if (initial) {
_histInited = true;
}
int32 toY = History::ScrollMax;
if (initial && hist->unreadBar) {
if (initial && hist->activeMsgId && !hist->lastWidth) {
HistoryItem *item = App::histItemById(hist->activeMsgId);
if (!item || item->detached()) {
hist->activeMsgId = 0;
return updateListSize(addToY, initial);
} else {
toY = (_scroll.height() > item->height()) ? qMax(item->y + item->block()->y - (_scroll.height() - item->height()) / 2, 0) : (item->y + item->block()->y);
_animActiveStart = getms();
_animActiveTimer.start(AnimationTimerDelta);
}
} else if (initial && hist->unreadBar) {
toY = hist->unreadBar->y + hist->unreadBar->block()->y;
} else if (hist->showFrom) {
toY = hist->showFrom->y + hist->showFrom->block()->y;
@ -2654,7 +2813,6 @@ void HistoryWidget::updateListSize(int32 addToY, bool initial) {
toY = newSt;
hist->lastWidth = 0;
} else {
int blabla = 0;
}
_scroll.scrollToY(toY);
}
@ -2666,6 +2824,13 @@ void HistoryWidget::addMessagesToFront(const QVector<MTPMessage> &messages) {
checkUnreadLoaded(true);
}
void HistoryWidget::addMessagesToBack(const QVector<MTPMessage> &messages) {
int32 sliceFrom = 0;
_list->messagesReceivedDown(messages);
updateListSize(0, false, true);
checkUnreadLoaded(true);
}
void HistoryWidget::mousePressEvent(QMouseEvent *e) {
}
@ -2784,6 +2949,22 @@ void HistoryWidget::onClearSelected() {
if (_list) _list->clearSelectedItems();
}
void HistoryWidget::onAnimActiveStep() {
if (!hist || !hist->activeMsgId) return _animActiveTimer.stop();
HistoryItem *item = App::histItemById(hist->activeMsgId);
if (!item || item->detached()) return _animActiveTimer.stop();
App::main()->msgUpdated(histPeer->id, item);
}
uint64 HistoryWidget::animActiveTime() const {
return _animActiveTimer.isActive() ? (getms() - _animActiveStart) : 0;
}
void HistoryWidget::stopAnimActive() {
_animActiveTimer.stop();
}
void HistoryWidget::updateTopBarSelection() {
if (!_list) {
App::main()->topBar()->showSelected(0);

View File

@ -40,6 +40,7 @@ public:
HistoryList(HistoryWidget *historyWidget, ScrollArea *scroll, History *history);
void messagesReceived(const QVector<MTPMessage> &messages);
void messagesReceivedDown(const QVector<MTPMessage> &messages);
bool event(QEvent *e); // calls touchEvent when necessary
void touchEvent(QTouchEvent *e);
@ -251,6 +252,7 @@ public:
void messagesReceived(const MTPmessages_Messages &messages, mtpRequestId requestId);
void windowShown();
bool isActive() const;
void resizeEvent(QResizeEvent *e);
void keyPressEvent(QKeyEvent *e);
@ -269,6 +271,7 @@ public:
void topBarClick();
void loadMessages();
void loadMessagesDown();
void peerMessagesUpdated(PeerId peer);
void peerMessagesUpdated();
@ -300,6 +303,7 @@ public:
PeerData *peer() const;
PeerData *activePeer() const;
MsgId activeMsgId() const;
void animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back = false);
bool animStep(float64 ms);
@ -314,6 +318,9 @@ public:
QString prepareMessage(QString text);
uint64 animActiveTime() const;
void stopAnimActive();
~HistoryWidget();
signals:
@ -334,6 +341,7 @@ public slots:
void onDocumentFailed(MsgId msgId);
void onListScroll();
void onHistoryToEnd();
void onSend();
void onPhotoSelect();
@ -343,7 +351,7 @@ public slots:
void onPhotoReady();
void onPhotoFailed(quint64 id);
void showPeer(const PeerId &peer, bool force = false, bool leaveActive = false);
void showPeer(const PeerId &peer, MsgId msgId = 0, bool force = false, bool leaveActive = false);
void activate();
void onTextChange();
@ -364,11 +372,14 @@ public slots:
void onDeleteContextSure();
void onClearSelected();
void onAnimActiveStep();
private:
bool messagesFailed(const RPCError &error, mtpRequestId requestId);
void updateListSize(int32 addToY = 0, bool initial = false);
void updateListSize(int32 addToY = 0, bool initial = false, bool loadedDown = false);
void addMessagesToFront(const QVector<MTPMessage> &messages);
void addMessagesToBack(const QVector<MTPMessage> &messages);
void chatLoaded(const MTPmessages_ChatFull &res);
QStringList getMediasFromMime(const QMimeData *d);
@ -376,18 +387,20 @@ private:
void updateDragAreas();
int32 histOffset, histCount, histReadRequestId;
int32 histRequestsCount;
PeerData *histPeer, *_activePeer;
PeerData *histPeer;
History *_activeHist;
MTPinputPeer histInputPeer;
mtpRequestId histPreloading;
QVector<MTPMessage> histPreload;
mtpRequestId histPreloading, histPreloadingDown;
QVector<MTPMessage> histPreload, histPreloadDown;
ScrollArea _scroll;
HistoryList *_list;
History *hist;
bool _histInited; // initial updateListSize() called
IconedButton _toHistoryEnd;
FlatButton _send;
IconedButton _attachDocument, _attachPhoto, _attachEmoji;
MessageField _field;
@ -422,5 +435,8 @@ private:
QTimer _scrollTimer;
int32 _scrollDelta;
QTimer _animActiveTimer;
float64 _animActiveStart;
};

View File

@ -85,7 +85,7 @@ void TopBarWidget::onDeleteContactSure() {
PeerData *p = App::main() ? App::main()->profilePeer() : 0;
UserData *u = (p && !p->chat) ? p->asUser() : 0;
if (u) {
App::main()->showPeer(0, true);
App::main()->showPeer(0, 0, true);
App::wnd()->hideLayer();
MTP::send(MTPcontacts_DeleteContact(u->inputUser), App::main()->rpcDone(&MainWidget::deletedContact, u));
}
@ -105,7 +105,7 @@ void TopBarWidget::onDeleteAndExitSure() {
PeerData *p = App::main() ? App::main()->profilePeer() : 0;
ChatData *c = (p && p->chat) ? p->asChat() : 0;
if (c) {
App::main()->showPeer(0, true);
App::main()->showPeer(0, 0, true);
App::wnd()->hideLayer();
MTP::send(MTPmessages_DeleteChatUser(MTP_int(p->id & 0xFFFFFFFF), App::self()->inputUser), App::main()->rpcDone(&MainWidget::deleteHistory, p), App::main()->rpcFail(&MainWidget::leaveChatFailed, p));
}
@ -266,7 +266,7 @@ MainWidget::MainWidget(Window *window) : QWidget(window), failedObjId(0), _dialo
setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight));
connect(window, SIGNAL(resized(const QSize &)), this, SLOT(onParentResize(const QSize &)));
connect(&dialogs, SIGNAL(peerChosen(const PeerId &)), this, SLOT(showPeer(const PeerId &)));
connect(&dialogs, SIGNAL(peerChosen(const PeerId &, MsgId)), this, SLOT(showPeer(const PeerId &, MsgId)));
connect(&dialogs, SIGNAL(cancelled()), this, SLOT(dialogsCancelled()));
connect(&history, SIGNAL(cancelled()), &dialogs, SLOT(activate()));
connect(this, SIGNAL(peerPhotoChanged(PeerData *)), this, SIGNAL(dialogsUpdated()));
@ -423,7 +423,7 @@ void MainWidget::addParticipants(ChatData *chat, const QVector<UserData*> &users
MTP::send(MTPmessages_AddChatUser(MTP_int(chat->id & 0xFFFFFFFF), (*i)->inputUser, MTP_int(ForwardOnAdd)), rpcDone(&MainWidget::addParticipantDone, chat), rpcFail(&MainWidget::addParticipantFail, chat), 0, 5);
}
App::wnd()->hideLayer();
showPeer(chat->id, false);
showPeer(chat->id, 0, false);
}
void MainWidget::addParticipantDone(ChatData *chat, const MTPmessages_StatedMessage &result) {
@ -439,7 +439,7 @@ bool MainWidget::addParticipantFail(ChatData *chat, const RPCError &e) {
void MainWidget::kickParticipant(ChatData *chat, UserData *user) {
MTP::send(MTPmessages_DeleteChatUser(MTP_int(chat->id & 0xFFFFFFFF), user->inputUser), rpcDone(&MainWidget::kickParticipantDone, chat), rpcFail(&MainWidget::kickParticipantFail, chat));
App::wnd()->hideLayer();
showPeer(chat->id, false);
showPeer(chat->id, 0, false);
}
void MainWidget::kickParticipantDone(ChatData *chat, const MTPmessages_StatedMessage &result) {
@ -476,9 +476,9 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu
}
dialogs.removePeer(peer);
} else {
if (App::historyLoaded(peer->id)) {
History *h = App::history(peer->id);
h->addToBack((*v)[0], false);
History *h = App::historyLoaded(peer->id);
if (!h->last) {
h->addToBack((*v)[0], 0);
}
}
}
@ -508,6 +508,8 @@ void MainWidget::sendMessage(History *hist, const QString &text) {
App::historyRegRandom(randomId, newId);
hist->loadAround(0);
MTPstring msgText(MTP_string(msg));
hist->addToBack(MTP_message(MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(hist->peer->id), MTP_bool(true), MTP_bool(true), MTP_int(unixtime()), msgText, MTP_messageMediaEmpty()));
historyToDown(hist);
@ -520,7 +522,7 @@ void MainWidget::sendMessage(History *hist, const QString &text) {
}
void MainWidget::readServerHistory(History *hist, bool force) {
if (!hist || (!force && (!hist->unreadCount || !hist->unreadLoaded))) return;
if (!hist || (!force && (!hist->unreadCount || !hist->readyForWork()))) return;
ReadRequests::const_iterator i = _readRequests.constFind(hist->peer);
if (i == _readRequests.cend()) {
@ -529,6 +531,14 @@ void MainWidget::readServerHistory(History *hist, bool force) {
}
}
uint64 MainWidget::animActiveTime() const {
return history.animActiveTime();
}
void MainWidget::stopAnimActive() {
history.stopAnimActive();
}
void MainWidget::partWasRead(PeerData *peer, const MTPmessages_AffectedHistory &result) {
const MTPDmessages_affectedHistory &d(result.c_messages_affectedHistory());
App::main()->updUpdated(d.vpts.v, 0, 0, d.vseq.v);
@ -713,7 +723,7 @@ bool MainWidget::getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w)
return false;
}
void MainWidget::showPeer(const PeerId &peerId, bool back, bool force) {
void MainWidget::showPeer(const PeerId &peerId, MsgId msgId, bool back, bool force) {
if (!back && profileStack.size() == 1 && profileStack[0]->id == peerId) {
back = true;
}
@ -738,7 +748,7 @@ void MainWidget::showPeer(const PeerId &peerId, bool back, bool force) {
history.show();
}
}
history.showPeer(peerId, force);
history.showPeer(peerId, msgId, force);
if (force || !selectingPeer()) {
if (profile) {
if (profile) profile->deleteLater();
@ -775,6 +785,10 @@ PeerData *MainWidget::activePeer() {
return history.activePeer();
}
MsgId MainWidget::activeMsgId() {
return history.activeMsgId();
}
PeerData *MainWidget::profilePeer() {
return profile ? profile->peer() : 0;
}
@ -798,7 +812,7 @@ void MainWidget::showPeerProfile(const PeerData *peer, bool back) {
resizeEvent(0);
profile->animShow(animCache, animTopBarCache, back);
history.animStop();
history.showPeer(0, false, true);
history.showPeer(0, 0, false, true);
history.hide();
_topBar.raise();
dialogs.raise();
@ -810,7 +824,7 @@ void MainWidget::showPeerBack() {
PeerData *peer = profileStack.back();
profileStack.pop_back();
if (profileStack.isEmpty()) {
showPeer(peer->id, true);
showPeer(peer->id, App::main()->activeMsgId(), true);
} else {
showPeerProfile(peer, true);
}
@ -971,7 +985,7 @@ void MainWidget::sentFullDatasReceived(const MTPmessages_StatedMessages &result)
void MainWidget::forwardDone(PeerId peer, const MTPmessages_StatedMessages &result) {
sentFullDatasReceived(result);
if (hider) hider->forwardDone();
showPeer(peer, false, true);
showPeer(peer, 0, false, true);
history.onClearSelected();
}
@ -991,7 +1005,7 @@ void MainWidget::dialogsToUp() {
}
void MainWidget::dialogsClear() {
dialogs.onCancel();
dialogs.clearFiltered();
}
void MainWidget::newUnreadMsg(History *hist, MsgId msgId) {
@ -1394,7 +1408,7 @@ bool MainWidget::isActive() const {
}
bool MainWidget::historyIsActive() const {
return isActive() && !profile;
return isActive() && !profile && history.isActive();
}
int32 MainWidget::dlgsWidth() const {
@ -1487,8 +1501,10 @@ void MainWidget::updateReceived(const mtpPrime *from, const mtpPrime *end) {
}
if (!App::userLoaded(d.vfrom_id.v)) return getDifference();
PeerId peer = App::histories().addToBack(MTP_message(d.vid, d.vfrom_id, MTP_peerUser(MTP_int(MTP::authedId())), MTP_bool(false), MTP_bool(true), d.vdate, d.vmessage, MTP_messageMediaEmpty()));
history.peerMessagesUpdated(peer);
HistoryItem *item = App::histories().addToBack(MTP_message(d.vid, d.vfrom_id, MTP_peerUser(MTP_int(MTP::authedId())), MTP_bool(false), MTP_bool(true), d.vdate, d.vmessage, MTP_messageMediaEmpty()));
if (item) {
history.peerMessagesUpdated(item->history()->peer->id);
}
updSetState(d.vpts.v, d.vdate.v, updQts, d.vseq.v);
} break;
@ -1500,8 +1516,10 @@ void MainWidget::updateReceived(const mtpPrime *from, const mtpPrime *end) {
}
if (!App::chatLoaded(d.vchat_id.v) || !App::userLoaded(d.vfrom_id.v)) return getDifference();
PeerId peer = App::histories().addToBack(MTP_message(d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), MTP_bool(false), MTP_bool(true), d.vdate, d.vmessage, MTP_messageMediaEmpty()));
history.peerMessagesUpdated(peer);
HistoryItem *item = App::histories().addToBack(MTP_message(d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), MTP_bool(false), MTP_bool(true), d.vdate, d.vmessage, MTP_messageMediaEmpty()));
if (item) {
history.peerMessagesUpdated(item->history()->peer->id);
}
updSetState(d.vpts.v, d.vdate.v, updQts, d.vseq.v);
} break;
@ -1523,8 +1541,10 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
switch (update.type()) {
case mtpc_updateNewMessage: {
const MTPDupdateNewMessage &d(update.c_updateNewMessage());
PeerId peer = App::histories().addToBack(d.vmessage);
history.peerMessagesUpdated(peer);
HistoryItem *item = App::histories().addToBack(d.vmessage);
if (item) {
history.peerMessagesUpdated(item->history()->peer->id);
}
if (updPts < d.vpts.v) updPts = d.vpts.v;
} break;
@ -1535,10 +1555,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
HistoryItem *msgRow = App::histItemById(msg);
if (msgRow) {
App::historyUnregItem(msgRow);
if (msgRow->id > 0) --msgRow->history()->offset;
msgRow->id = d.vid.v;
if (msgRow->id > 0) ++msgRow->history()->offset;
if (App::historyRegItem(msgRow)) {
if (!App::historyRegItem(msgRow)) {
msgUpdated(msgRow->history()->peer->id, msgRow);
} else {
msgRow->destroy();
@ -1635,7 +1653,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
if (false && !d.vprevious.v && d.vuser_id.v != MTP::authedId() && d.vphoto.type() == mtpc_userProfilePhoto) {
MTPPhoto photo(App::photoFromUserPhoto(MTP_int(user->id & 0xFFFFFFFF), d.vdate, d.vphoto));
HistoryMedia *media = new HistoryPhoto(photo.c_photo(), 100);
App::history(user->id)->addToBackService(clientMsgId(), date(d.vdate), lang(lng_action_user_photo).replace(qsl("{from}"), user->name), false, true, media);
if (App::history(user->id)->loadedAtBottom()) {
App::history(user->id)->addToBackService(clientMsgId(), date(d.vdate), lang(lng_action_user_photo).replace(qsl("{from}"), user->name), false, true, media);
}
}
if (App::main()) App::main()->peerUpdated(user);
}
@ -1645,7 +1665,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
const MTPDupdateContactRegistered &d(update.c_updateContactRegistered());
UserData *user = App::userLoaded(d.vuser_id.v);
if (user) {
App::history(user->id)->addToBackService(clientMsgId(), date(d.vdate), lang(lng_action_user_registered).replace(qsl("{from}"), user->name), false, true);
if (App::history(user->id)->loadedAtBottom()) {
App::history(user->id)->addToBackService(clientMsgId(), date(d.vdate), lang(lng_action_user_registered).replace(qsl("{from}"), user->name), false, true);
}
}
} break;

View File

@ -134,6 +134,7 @@ public:
PeerData *peerAfter(const PeerData *peer);
PeerData *peer();
PeerData *activePeer();
MsgId activeMsgId();
PeerData *profilePeer();
void showPeerProfile(const PeerData *peer, bool back = false);
void showPeerBack();
@ -193,6 +194,9 @@ public:
void readServerHistory(History *history, bool force = true);
uint64 animActiveTime() const;
void stopAnimActive();
~MainWidget();
signals:
@ -201,6 +205,7 @@ signals:
void peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
void peerPhotoChanged(PeerData *peer);
void dialogRowReplaced(DialogRow *oldRow, DialogRow *newRow);
void historyItemReplaced(HistoryItem *oldItem, HistoryItem *newItem);
void dialogToTop(const History::DialogLinks &links);
void dialogsUpdated();
void historyItemDeleted(HistoryItem *item);
@ -227,7 +232,7 @@ public slots:
void mainStateChanged(Qt::WindowState state);
void updateOnlineDisplay();
void showPeer(const PeerId &peer, bool back = false, bool force = false);
void showPeer(const PeerId &peer, MsgId msgId = 0, bool back = false, bool force = false);
void onTopBarClick();
void onPeerShown(PeerData *peer);

View File

@ -189,19 +189,13 @@ with open('scheme.tl') as f:
funcsText += '\tmtpTypeId type() const {\n\t\treturn mtpc_' + name + ';\n\t}\n'; # type id
if (len(prmsList)):
funcsText += '\tvoid read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId /*cons*/ = mtpc_' + name + ') {\n'; # read method
else:
funcsText += '\tvoid read(const mtpPrime *&/*from*/, const mtpPrime */*end*/, mtpTypeId /*cons*/ = mtpc_' + name + ') {\n'; # read method
funcsText += '\tvoid read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_' + name + ') {\n'; # read method
for k in prmsList:
v = prms[k];
funcsText += '\t\tv' + k + '.read(from, end);\n';
funcsText += '\t}\n';
if (len(prmsList)):
funcsText += '\tvoid write(mtpBuffer &to) const {\n'; # write method
else:
funcsText += '\tvoid write(mtpBuffer &/*to*/) const {\n'; # write method
funcsText += '\tvoid write(mtpBuffer &to) const {\n'; # write method
for k in prmsList:
v = prms[k];
funcsText += '\t\tv' + k + '.write(to);\n';
@ -538,10 +532,7 @@ for restype in typesList:
inlineMethods += '}\n';
typesText += '\tvoid write(mtpBuffer &to) const;\n'; # write method
if (len(writer)):
inlineMethods += 'inline void MTP' + restype + '::write(mtpBuffer &to) const {\n';
else:
inlineMethods += 'inline void MTP' + restype + '::write(mtpBuffer &/*to*/) const {\n';
inlineMethods += 'inline void MTP' + restype + '::write(mtpBuffer &to) const {\n';
if (withType):
inlineMethods += '\tswitch (_type) {\n';
inlineMethods += writer;

View File

@ -41,6 +41,7 @@ inline bool mtpRequestData::needAckByType(mtpTypeId type) {
case mtpc_http_wait:
case mtpc_bad_msg_notification:
case mtpc_msgs_all_info:
case mtpc_msgs_state_info:
case mtpc_msg_detailed_info:
case mtpc_msg_new_detailed_info:
return false;

View File

@ -328,6 +328,7 @@ enum {
mtpc_invokeWithLayer12 = 0xdda60d3c,
mtpc_invokeWithLayer13 = 0x427c8ea2,
mtpc_invokeWithLayer14 = 0x2b9b08fa,
mtpc_invokeWithLayer15 = 0xb4418b64,
// manually parsed
mtpc_rpc_result = 0xf35c6d01,
@ -352,6 +353,7 @@ static const mtpTypeId mtpLayers[] = {
mtpc_invokeWithLayer12,
mtpc_invokeWithLayer13,
mtpc_invokeWithLayer14,
mtpc_invokeWithLayer15,
}, mtpLayerMax = sizeof(mtpLayers) / sizeof(mtpLayers[0]);
template <typename bareT>

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,7 @@
//invokeWithLayer12#dda60d3c query:!X = X;
//invokeWithLayer13#427c8ea2 query:!X = X;
//invokeWithLayer14#2b9b08fa query:!X = X;
//invokeWithLayer15#b4418b64 query:!X = X;
///////////////////////////////
/// Authorization key creation
@ -123,6 +124,7 @@ register.saveDeveloperInfo#9a5f6e95 name:string email:string phone_number:string
---types---
inputPeerEmpty#7f3b18ea = InputPeer;
inputPeerSelf#7da07ec9 = InputPeer;
inputPeerContact#1023dbe8 user_id:int = InputPeer;
@ -340,6 +342,7 @@ inputMessagesFilterPhotos#9609a51c = MessagesFilter;
inputMessagesFilterVideo#9fc00e65 = MessagesFilter;
inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter;
inputMessagesFilterDocument#9eddf188 = MessagesFilter;
inputMessagesFilterAudio#cfc87522 = MessagesFilter;
updateNewMessage#13abdb3 message:Message pts:int = Update;
updateMessageID#4e90bfd6 id:int random_id:long = Update;

View File

@ -171,7 +171,7 @@ void ProfileInner::onClearHistory() {
}
void ProfileInner::onClearHistorySure() {
App::main()->showPeer(0, true);
App::main()->showPeer(0, 0, true);
App::wnd()->hideLayer();
App::main()->clearHistory(_peer);
}
@ -546,7 +546,7 @@ void ProfileInner::onKickConfirm() {
void ProfileInner::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Escape) {
App::main()->showPeer(0, true);
App::main()->showPeer(0, 0, true);
}
}

View File

@ -1393,12 +1393,12 @@ PsMainWindow::~PsMainWindow() {
}
void PsMainWindow::psNotify(History *history, MsgId msgId) {
if (App::quiting() || !history->notifyFrom) return;
if (App::quiting() || !history->currentNotification()) return;
bool haveSetting = (history->peer->notify != UnknownNotifySettings);
if (haveSetting) {
if (history->peer->notify != EmptyNotifySettings && history->peer->notify->mute > unixtime()) {
history->clearNotifyFrom();
history->clearNotifications();
return;
}
} else {
@ -1454,7 +1454,7 @@ void PsMainWindow::psClearNotify(History *history) {
(*i)->unlinkHistory();
}
for (NotifyWhenMaps::const_iterator i = notifyWhenMaps.cbegin(), e = notifyWhenMaps.cend(); i != e; ++i) {
i.key()->clearNotifyFrom();
i.key()->clearNotifications();
}
notifyWaiters.clear();
notifySettingWaiters.clear();
@ -1588,24 +1588,24 @@ void PsMainWindow::psShowNextNotify(PsNotifyWindow *remove) {
NotifyWaiters::iterator notifyWaiter;
for (NotifyWaiters::iterator i = notifyWaiters.begin(); i != notifyWaiters.end(); ++i) {
History *history = i.key();
if (history->notifyFrom && history->notifyFrom->id != i.value().msg) {
if (history->currentNotification() && history->currentNotification()->id != i.value().msg) {
NotifyWhenMaps::iterator j = notifyWhenMaps.find(history);
if (j == notifyWhenMaps.end()) {
history->clearNotifyFrom();
history->clearNotifications();
i = notifyWaiters.erase(i);
continue;
}
do {
NotifyWhenMap::const_iterator k = j.value().constFind(history->notifyFrom->id);
NotifyWhenMap::const_iterator k = j.value().constFind(history->currentNotification()->id);
if (k != j.value().cend()) {
i.value().msg = k.key();
i.value().when = k.value();
break;
}
history->getNextNotifyFrom();
} while (history->notifyFrom);
history->skipNotification();
} while (history->currentNotification());
}
if (!history->notifyFrom) {
if (!history->currentNotification()) {
notifyWhenMaps.remove(history);
i = notifyWaiters.erase(i);
continue;
@ -1613,7 +1613,7 @@ void PsMainWindow::psShowNextNotify(PsNotifyWindow *remove) {
uint64 when = i.value().when;
if (!notifyItem || next > when) {
next = when;
notifyItem = history->notifyFrom;
notifyItem = history->currentNotification();
notifyWaiter = i;
}
}
@ -1631,25 +1631,25 @@ void PsMainWindow::psShowNextNotify(PsNotifyWindow *remove) {
uint64 ms = getms();
History *history = notifyItem->history();
history->getNextNotifyFrom();
history->skipNotification();
NotifyWhenMaps::iterator j = notifyWhenMaps.find(history);
if (j == notifyWhenMaps.end() || !history->notifyFrom) {
history->clearNotifyFrom();
if (j == notifyWhenMaps.end() || !history->currentNotification()) {
history->clearNotifications();
notifyWaiters.erase(notifyWaiter);
if (j != notifyWhenMaps.end()) notifyWhenMaps.erase(j);
continue;
}
j.value().remove(notifyItem->id);
do {
NotifyWhenMap::const_iterator k = j.value().constFind(history->notifyFrom->id);
NotifyWhenMap::const_iterator k = j.value().constFind(history->currentNotification()->id);
if (k != j.value().cend()) {
notifyWaiter.value().msg = k.key();
notifyWaiter.value().when = k.value();
break;
}
history->getNextNotifyFrom();
} while (history->notifyFrom);
if (!history->notifyFrom) {
history->skipNotification();
} while (history->currentNotification());
if (!history->currentNotification()) {
notifyWaiters.erase(notifyWaiter);
notifyWhenMaps.erase(j);
continue;
@ -1829,7 +1829,7 @@ void PsNotifyWindow::mousePressEvent(QMouseEvent *e) {
} else if (history) {
App::wnd()->showFromTray();
App::wnd()->hideSettings();
App::main()->showPeer(history->peer->id, false, true);
App::main()->showPeer(history->peer->id, 0, false, true);
e->ignore();
}
}

View File

@ -56,6 +56,7 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
#include "gui/flatinput.h"
#include "gui/flattextarea.h"
#include "gui/flatbutton.h"
#include "gui/switcher.h"
#include "gui/scrollarea.h"
#include "gui/images.h"
#include "gui/text.h"

Binary file not shown.

View File

@ -314,6 +314,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_switcher.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_sysbuttons.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@ -498,6 +502,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_switcher.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_sysbuttons.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@ -691,6 +699,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_switcher.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_sysbuttons.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@ -740,6 +752,7 @@
<ClCompile Include="SourceFiles\gui\flatbutton.cpp" />
<ClCompile Include="SourceFiles\gui\scrollarea.cpp" />
<ClCompile Include="SourceFiles\gui\style_core.cpp" />
<ClCompile Include="SourceFiles\gui\switcher.cpp" />
<ClCompile Include="SourceFiles\gui\text.cpp" />
<ClCompile Include="SourceFiles\gui\twidget.cpp" />
<ClCompile Include="SourceFiles\history.cpp" />
@ -1213,6 +1226,20 @@
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
</CustomBuild>
<ClInclude Include="SourceFiles\gui\style_core.h" />
<CustomBuild Include="SourceFiles\gui\switcher.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">Moc%27ing switcher.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/switcher.h" -DCUSTOM_API_ID -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing switcher.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/gui/switcher.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing switcher.h...</Message>
<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/gui/switcher.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.0\QtGui"</Command>
</CustomBuild>
<ClInclude Include="SourceFiles\gui\text.h" />
<ClInclude Include="SourceFiles\history.h" />
<CustomBuild Include="SourceFiles\historywidget.h">

View File

@ -656,6 +656,18 @@
<ClCompile Include="GeneratedFiles\Release\moc_aboutbox.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
<ClCompile Include="SourceFiles\gui\switcher.cpp">
<Filter>gui</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_switcher.cpp">
<Filter>Generated Files\Deploy</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_switcher.cpp">
<Filter>Generated Files\Debug</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_switcher.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="SourceFiles\stdafx.h">
@ -891,6 +903,9 @@
<Filter>gui</Filter>
</CustomBuild>
<CustomBuild Include="Resources\lang.txt" />
<CustomBuild Include="SourceFiles\gui\switcher.h">
<Filter>gui</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<Image Include="SourceFiles\art\icon.png">