From b676158117abfadfb2dcbad6b2c7269fe92d9809 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 13 Jul 2014 13:50:38 +0400 Subject: [PATCH] prepared 0.5.7 version with serverside search and some fixes --- Telegram/Resources/lang.txt | 4 + Telegram/Resources/style.txt | 6 + Telegram/SourceFiles/app.cpp | 2 +- Telegram/SourceFiles/art/icon.png | Bin 5027 -> 0 bytes Telegram/SourceFiles/art/iconf.png | Bin 3187 -> 0 bytes Telegram/SourceFiles/config.h | 16 +- Telegram/SourceFiles/dialogswidget.cpp | 306 ++++++++++++++----------- Telegram/SourceFiles/dialogswidget.h | 20 +- Telegram/SourceFiles/gui/text.cpp | 2 +- Telegram/SourceFiles/history.cpp | 16 +- Telegram/SourceFiles/history.h | 1 + Telegram/SourceFiles/historywidget.cpp | 51 ++++- Telegram/SourceFiles/historywidget.h | 5 + Telegram/SourceFiles/mtproto/mtp.cpp | 5 + Telegram/SourceFiles/mtproto/mtp.h | 1 + Telegram/SourceFiles/mtproto/mtpDC.cpp | 13 ++ Telegram/SourceFiles/mtproto/mtpDC.h | 1 + Telegram/Telegram.vcxproj | 22 -- Telegram/Telegram.vcxproj.filters | 14 -- 19 files changed, 291 insertions(+), 194 deletions(-) delete mode 100644 Telegram/SourceFiles/art/icon.png delete mode 100644 Telegram/SourceFiles/art/iconf.png diff --git a/Telegram/Resources/lang.txt b/Telegram/Resources/lang.txt index 3a4d9273f..3855a3231 100644 --- a/Telegram/Resources/lang.txt +++ b/Telegram/Resources/lang.txt @@ -382,6 +382,10 @@ This software is licensed under [a href=\"https://github.com/telegramdesktop/tde source code is available on [a href=\"https://github.com/telegramdesktop/tdesktop\"]GitHub[/a]."; lng_about_done: "Done"; +lng_search_no_results: "No messages found"; +lng_search_one_result: "Found {count} message"; +lng_search_n_results: "Found {count} messages"; + // Mac specific lng_mac_choose_app: "Choose Application"; diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index f95169460..b37b5be5b 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -958,6 +958,12 @@ unreadBarBG: #fcfbfa; unreadBarBorder: titleShadowColor; unreadBarColor: #538bb4; +searchedBarHeight: unreadBarHeight; +searchedBarFont: unreadBarFont; +searchedBarBG: #f1f1f1; +searchedBarBorder: unreadBarBorder; +searchedBarColor: #aaa; + layerSlideDuration: 200; layerHideDuration: 200; layerPadding: margins(10px, 10px, 10px, 10px); diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 517a53bf1..2ce103048 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -133,7 +133,7 @@ namespace App { } void logOut() { - MTP::send(MTPauth_LogOut(), rpcDone(&loggedOut), rpcFail(&loggedOut)); + MTP::logoutKeys(rpcDone(&loggedOut), rpcFail(&loggedOut)); } PeerId peerFromMTP(const MTPPeer &peer_id) { diff --git a/Telegram/SourceFiles/art/icon.png b/Telegram/SourceFiles/art/icon.png deleted file mode 100644 index 4e53389ae64fe2ab12cb2655a0e96f013ba2f552..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5027 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 tSoy>1^z`mdi%&@O diff --git a/Telegram/SourceFiles/art/iconf.png b/Telegram/SourceFiles/art/iconf.png deleted file mode 100644 index fa9c541a6d2b8d344fcf35f7c52315f1e1ee4823..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3187 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 Z0{}Ubd~X?3C%*sy002ovPDHLkV1h|FGTi_G diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 52ebb0aae..99d1b64ad 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -17,8 +17,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com */ #pragma once -static const int32 AppVersion = 5006; -static const wchar_t *AppVersionStr = L"0.5.6"; +static const int32 AppVersion = 5007; +static const wchar_t *AppVersionStr = L"0.5.7"; #ifdef Q_OS_WIN static const wchar_t *AppName = L"Telegram Win (Unofficial)"; #else @@ -60,7 +60,7 @@ enum { SaveRecentEmojisTimeout = 3000, // 3 secs - AutoSearchTimeout = 1500, // 1.5 secs + AutoSearchTimeout = 900, // 0.9 secs SearchPerPage = 50, }; @@ -116,10 +116,20 @@ static const char *ApiHash = "344583e45741c457fe1862106095a5eb"; #endif inline const char *cApiDeviceModel() { +#ifdef Q_OS_WIN return "x86 desktop"; +#else + return "x64 desktop"; +#endif } inline const char *cApiSystemVersion() { +#ifdef Q_OS_WIN return "windows"; +#elif defined Q_OS_MAC + return "os x"; +#elif defined Q_OS_LINUX + return "linux"; +#endif } inline QString cApiAppVersion() { return QString::number(AppVersion); diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index 13802c6c6..30a3d7854 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -26,16 +26,13 @@ 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), searchedSel(-1), _state(DefaultState) { + dialogs(false), contactsNoDialogs(true), contacts(true), sel(0), contactSel(false), selByMouse(false), filteredSel(-1), searchedCount(0), 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) { @@ -58,33 +55,42 @@ void DialogsListWidget::paintEvent(QPaintEvent *e) { } else if (!otherStart) { // .. paint no dialogs found } - } else if (_state == FilteredState) { + } else if (_state == FilteredState || _state == SearchedState) { if (filterResults.isEmpty()) { // .. paint no dialogs } else { int32 from = r.top() / int32(st::dlgHeight); - if (from < 0) from = 0; + if (from < 0) { + from = 0; + } else if (from > filterResults.size()) { + from = filterResults.size(); + } + p.translate(0, from * st::dlgHeight); if (from < filterResults.size()) { int32 to = (r.bottom() / int32(st::dlgHeight)) + 1, w = width(); if (to > filterResults.size()) to = filterResults.size(); - - p.translate(0, from * st::dlgHeight); for (; from < to; ++from) { - bool active = (filterResults[from]->history->peer == App::main()->activePeer()); + bool active = (filterResults[from]->history->peer == App::main()->activePeer() && !App::main()->activeMsgId()); bool selected = (from == filteredSel); 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 (_state == SearchedState || !searchResults.isEmpty()) { + QString text = searchResults.isEmpty() ? lang(lng_search_no_results) : lang(searchedCount > 1 ? lng_search_n_results : lng_search_one_result).replace(qsl("{count}"), QString::number(searchedCount)); + p.fillRect(0, 0, width(), st::searchedBarHeight, st::searchedBarBG->b); + p.setFont(st::searchedBarFont->f); + p.setPen(st::searchedBarColor->p); + p.drawText(QRect(0, 0, width(), st::searchedBarHeight), text, style::al_center); + p.translate(0, st::searchedBarHeight); + + int32 skip = filterResults.size() * st::dlgHeight + st::searchedBarHeight; + int32 from = (r.top() - skip) / int32(st::dlgHeight); if (from < 0) from = 0; if (from < searchResults.size()) { - int32 to = (r.bottom() / int32(st::dlgHeight)) + 1, w = width(); + int32 to = ((r.bottom() - skip) / int32(st::dlgHeight)) + 1, w = width(); if (to > searchResults.size()) to = searchResults.size(); p.translate(0, from * st::dlgHeight); @@ -100,11 +106,7 @@ void DialogsListWidget::paintEvent(QPaintEvent *e) { } void DialogsListWidget::activate() { - if ( - (_state == DefaultState && !sel) || - (_state == FilteredState && (filteredSel < 0 || filteredSel >= filterResults.size())) || - (_state == SearchedState && (searchedSel < 0 || searchedSel >= searchResults.size())) - ) { + if (_state == DefaultState && !sel) { selectSkip(1); } } @@ -135,7 +137,7 @@ void DialogsListWidget::onUpdateSelected(bool force) { setCursor(sel ? style::cur_pointer : style::cur_default); parentWidget()->update(); } - } else if (_state == FilteredState) { + } else if (_state == FilteredState || _state == SearchedState) { if (!filterResults.isEmpty()) { int32 newFilteredSel = mouseY / int32(st::dlgHeight); if (newFilteredSel < 0 || newFilteredSel >= filterResults.size()) { @@ -147,9 +149,9 @@ void DialogsListWidget::onUpdateSelected(bool force) { parentWidget()->update(); } } - } else if (_state == SearchedState) { - if (!searchResults.isEmpty()) { - int32 newSearchedSel = mouseY / int32(st::dlgHeight); + if (_state == SearchedState && !searchResults.isEmpty()) { + mouseY -= filterResults.size() * st::dlgHeight + st::searchedBarHeight; + int32 newSearchedSel = (mouseY >= 0) ? mouseY / int32(st::dlgHeight) : -1; if (newSearchedSel < 0 || newSearchedSel >= searchResults.size()) { newSearchedSel = -1; } @@ -172,7 +174,7 @@ void DialogsListWidget::mousePressEvent(QMouseEvent *e) { } void DialogsListWidget::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) { - if (_state == FilteredState) { + if (_state == FilteredState || _state == SearchedState) { 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) { @@ -243,7 +245,7 @@ void DialogsListWidget::removeContact(UserData *user) { void DialogsListWidget::dlgUpdated(DialogRow *row) { if (_state == DefaultState) { update(0, row->pos * st::dlgHeight, width(), st::dlgHeight); - } else if (_state == FilteredState) { + } else if (_state == FilteredState || _state == SearchedState) { int32 cnt = 0; for (FilteredDialogs::const_iterator i = filterResults.cbegin(), e = filterResults.cend(); i != e; ++i) { if ((*i)->history == row->history) { @@ -267,7 +269,7 @@ void DialogsListWidget::dlgUpdated(History *history) { update(0, (dialogs.list.count + i.value()->pos) * st::dlgHeight, width(), st::dlgHeight); } } - } else if (_state == FilteredState) { + } else if (_state == FilteredState || _state == SearchedState) { int32 cnt = 0; for (FilteredDialogs::const_iterator i = filterResults.cbegin(), e = filterResults.cend(); i != e; ++i) { if ((*i)->history == history) { @@ -276,14 +278,15 @@ void DialogsListWidget::dlgUpdated(History *history) { } ++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; + if (!searchResults.isEmpty()) { + int32 cnt = 0, add = filterResults.size() * st::dlgHeight + st::searchedBarHeight; + for (SearchResults::const_iterator i = searchResults.cbegin(), e = searchResults.cend(); i != e; ++i) { + if ((*i)->_item->history() == history) { + update(0, add + cnt * st::dlgHeight, width(), st::dlgHeight); + break; + } + ++cnt; } - ++cnt; } } } @@ -331,11 +334,6 @@ void DialogsListWidget::onPeerPhotoChanged(PeerData *peer) { } 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 || force) { QStringList f; @@ -356,6 +354,7 @@ void DialogsListWidget::onFilterUpdate(QString newFilter, bool force) { if (filter.isEmpty()) { _state = DefaultState; filterResults.clear(); + searchResults.clear(); } else { QStringList::const_iterator fb = f.cbegin(), fe = f.cend(), fi; @@ -434,6 +433,9 @@ void DialogsListWidget::onFilterUpdate(QString newFilter, bool force) { refresh(true); setMouseSel(false, true); } + if (_state != DefaultState) { + emit searchMessages(); + } } DialogsListWidget::~DialogsListWidget() { @@ -485,7 +487,7 @@ void DialogsListWidget::dialogsReceived(const QVector &added) { refresh(); } -void DialogsListWidget::searchReceived(const QVector &messages, bool fromStart) { +void DialogsListWidget::searchReceived(const QVector &messages, bool fromStart, int32 fullCount) { if (fromStart) { clearSearchResults(); } @@ -493,6 +495,10 @@ void DialogsListWidget::searchReceived(const QVector &messages, bool HistoryItem *item = App::histories().addToBack(*i, -1); searchResults.push_back(new FakeDialogRow(item)); } + searchedCount = fullCount; + if (_state == FilteredState) { + _state = SearchedState; + } refresh(); } @@ -531,15 +537,15 @@ int32 DialogsListWidget::addNewContact(int32 uid, bool select) { } void DialogsListWidget::refresh(bool toTop) { - int32 cnt = 0; + int32 h = 0; if (_state == DefaultState) { - cnt = dialogs.list.count + contactsNoDialogs.list.count; + h = (dialogs.list.count + contactsNoDialogs.list.count) * st::dlgHeight; } else if (_state == FilteredState) { - cnt = filterResults.count(); + h = (filterResults.count() + searchResults.count()) * st::dlgHeight + (searchResults.isEmpty() ? 0 : st::searchedBarHeight); } else if (_state == SearchedState) { - cnt = searchResults.count(); + h = (filterResults.count() + searchResults.count()) * st::dlgHeight + st::searchedBarHeight; } - resize(width(), cnt * st::dlgHeight); + resize(width(), h); if (toTop) { emit mustScrollTo(0, 0); loadPeerPhotos(0); @@ -553,19 +559,18 @@ void DialogsListWidget::setMouseSel(bool msel, bool toTop) { 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 if (_state == FilteredState) { - filteredSel = 0; - } else if (_state == SearchedState) { - searchedSel = -1; // don't select first elem in search + } else if (_state == FilteredState || _state == SearchedState) { // don't select first elem in search + filteredSel = -1; + searchedSel = -1; } } } void DialogsListWidget::setState(State newState) { _state = newState; - if (_state == DefaultState || _state == FilteredState) { + if (_state == DefaultState) { clearSearchResults(); - searchedSel = -1; + searchedSel = filteredSel = -1; } else if (_state == DefaultState || _state == SearchedState) { filterResults.clear(); filteredSel = -1; @@ -579,8 +584,10 @@ DialogsListWidget::State DialogsListWidget::state() const { } void DialogsListWidget::clearFilter() { - if (_state == FilteredState) { + if (_state == FilteredState || _state == SearchedState) { _state = DefaultState; + filterResults.clear(); + searchResults.clear(); filter = QString(); refresh(true); } @@ -596,6 +603,7 @@ void DialogsListWidget::addDialog(const MTPDdialog &dialog) { } void DialogsListWidget::selectSkip(int32 direction) { + int32 skipMore = 0; if (_state == DefaultState) { if (!sel) { if (dialogs.list.count && direction > 0) { @@ -622,22 +630,56 @@ void DialogsListWidget::selectSkip(int32 direction) { } int32 fromY = (sel->pos + (contactSel ? dialogs.list.count : 0)) * st::dlgHeight; emit mustScrollTo(fromY, fromY + st::dlgHeight); - } else if (_state == FilteredState) { - if (filterResults.isEmpty()) return; - int32 newSel = snap(filteredSel + direction, 0, filterResults.size() - 1); - if (newSel != filteredSel) { - filteredSel = newSel; + } else if (_state == FilteredState || _state == SearchedState) { + if (filterResults.isEmpty() && searchResults.isEmpty()) return; + if (filteredSel < 0 || filteredSel >= filterResults.size()) { + if (searchedSel < 0 || searchedSel >= searchResults.size()) { + if (filterResults.isEmpty()) { + searchedSel = 0; + } else { + filteredSel = 0; + } + } else if (direction < 0 && !searchedSel && !filterResults.isEmpty()) { + searchedSel = -1; + filteredSel = filterResults.size() + direction; + if (filteredSel < 0) filteredSel = 0; + } else { + if (direction < -1 && searchedSel + direction < 0) { + skipMore = direction + searchedSel; + if (skipMore == direction) { + skipMore = 0; + } else { + direction -= skipMore; + } + } + searchedSel = snap(searchedSel + direction, 0, searchResults.size() - 1); + } + } else if (direction > 0 && filteredSel == filterResults.size() - 1 && !searchResults.isEmpty()) { + filteredSel = -1; + searchedSel = direction - 1; + if (searchedSel > searchResults.size() - 1) searchedSel = searchResults.size() - 1; + } else { + if (direction > 1 && filteredSel + direction > filterResults.size() - 1) { + skipMore = direction - (filterResults.size() - 1 - filteredSel); + if (skipMore == direction) { + skipMore = 0; + } else { + direction -= skipMore; + } + } + filteredSel = snap(filteredSel + direction, 0, filterResults.size() - 1); } - 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; + if (filteredSel >= 0 && filteredSel < filterResults.size()) { + emit mustScrollTo(filteredSel * st::dlgHeight, (filteredSel + 1) * st::dlgHeight); + } else { + emit mustScrollTo((searchedSel + filterResults.size()) * st::dlgHeight + (searchedSel ? st::searchedBarHeight : 0), (searchedSel + filterResults.size() + 1) * st::dlgHeight + st::searchedBarHeight); } - emit mustScrollTo(searchedSel * st::dlgHeight, (searchedSel + 1) * st::dlgHeight); } - parentWidget()->update(); + if (skipMore) { + return selectSkip(skipMore); + } else { + parentWidget()->update(); + } } void DialogsListWidget::scrollToPeer(const PeerId &peer) { @@ -729,7 +771,7 @@ void DialogsListWidget::loadPeerPhotos(int32 yFrom) { row->history->peer->photo->load(); } } - } else if (_state == FilteredState) { + } else if (_state == FilteredState || _state == SearchedState) { int32 from = yFrom / st::dlgHeight; if (from < 0) from = 0; if (from < filterResults.size()) { @@ -740,11 +782,11 @@ void DialogsListWidget::loadPeerPhotos(int32 yFrom) { filterResults[from]->history->peer->photo->load(); } } - } else if (_state == SearchedState) { - int32 from = yFrom / st::dlgHeight; + + from = (yFrom > st::searchedBarHeight ? ((yFrom - st::searchedBarHeight) / int32(st::dlgHeight)) : 0) - filterResults.size(); if (from < 0) from = 0; if (from < searchResults.size()) { - int32 to = (yTo / int32(st::dlgHeight)) + 1, w = width(); + int32 to = (yTo > st::searchedBarHeight ? ((yTo - st::searchedBarHeight) / int32(st::dlgHeight)) : 0) - filterResults.size() + 1, w = width(); if (to > searchResults.size()) to = searchResults.size(); for (; from < to; ++from) { @@ -759,10 +801,10 @@ bool DialogsListWidget::choosePeer() { 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()) { + } else if (_state == FilteredState || _state == SearchedState) { + if (filteredSel >= 0 && filteredSel < filterResults.size()) { + history = filterResults[filteredSel]->history; + } else if (searchedSel >= 0 && searchedSel < searchResults.size()) { history = searchResults[searchedSel]->_item->history(); msgId = searchResults[searchedSel]->_item->id; } @@ -808,7 +850,7 @@ PeerData *DialogsListWidget::peerBefore(const PeerData *peer) const { if (i.value()->prev) { return i.value()->prev->history->peer; } - } else if (_state == FilteredState) { + } else if (_state == FilteredState || _state == SearchedState) { if (filterResults.isEmpty() || filterResults.at(0)->history->peer == peer) return 0; for (FilteredDialogs::const_iterator b = filterResults.cbegin(), i = b + 1, e = filterResults.cend(); i != e; ++i) { @@ -840,7 +882,7 @@ PeerData *DialogsListWidget::peerAfter(const PeerData *peer) const { } else if (contactsNoDialogs.list.count) { return contactsNoDialogs.list.begin->history->peer; } - } else if (_state == FilteredState) { + } else if (_state == FilteredState || _state == SearchedState) { for (FilteredDialogs::const_iterator i = filterResults.cbegin(), e = filterResults.cend(); i != e; ++i) { if ((*i)->history->peer == peer) { ++i; @@ -871,7 +913,6 @@ 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) @@ -883,9 +924,8 @@ DialogsWidget::DialogsWidget(MainWidget *parent) : QWidget(parent) 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 &, 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(&list, SIGNAL(searchMessages()), this, SLOT(onNeedSearchMessages())); connect(&scroll, SIGNAL(geometryChanged()), &list, SLOT(onParentGeometryChanged())); connect(&scroll, SIGNAL(scrolled()), &list, SLOT(onUpdateSelected())); connect(&scroll, SIGNAL(scrolled()), this, SLOT(onListScroll())); @@ -896,16 +936,12 @@ DialogsWidget::DialogsWidget(MainWidget *parent) : QWidget(parent) 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())); + _searchTimer.setSingleShot(true); + connect(&_searchTimer, SIGNAL(timeout()), this, SLOT(onSearchMessages())); 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(); @@ -981,9 +1017,7 @@ void DialogsWidget::onCancel() { } void DialogsWidget::clearFiltered() { - if (list.state() != DialogsListWidget::SearchedState) { - onCancel(); - } + onCancel(); } void DialogsWidget::unreadCountsReceived(const QVector &dialogs) { @@ -1051,29 +1085,45 @@ bool DialogsWidget::dialogsFailed(const RPCError &e) { return true; } -void DialogsWidget::onSearchMessages(bool force) { +bool DialogsWidget::onSearchMessages(bool searchCache) { QString q = _filter.text().trimmed(); if (q.isEmpty()) { if (_searchRequest) { - MTP::cancel(_searchRequest); _searchRequest = 0; } - if (force) { - list.setState(DialogsListWidget::DefaultState); - } - return; + return true; } - if (force || _searchQuery != q) { - if (_searchRequest) MTP::cancel(_searchRequest); + if (searchCache) { + SearchCache::const_iterator i = _searchCache.constFind(q); + if (i != _searchCache.cend()) { + _searchQuery = q; + _searchFull = false; + _searchRequest = 0; + searchReceived(true, i.value(), 0); + return true; + } + } else if (_searchQuery != q) { _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)); + _searchQueries.insert(_searchRequest, _searchQuery); + } + return false; +} + + +void DialogsWidget::onNeedSearchMessages() { + if (!onSearchMessages(true)) { + _searchTimer.start(AutoSearchTimeout); } } 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)); + if (!minMsgId) { + _searchQueries.insert(_searchRequest, _searchQuery); + } } } @@ -1108,13 +1158,21 @@ bool DialogsWidget::contactsFailed() { } void DialogsWidget::searchReceived(bool fromStart, const MTPmessages_Messages &result, mtpRequestId req) { + if (fromStart && (list.state() == DialogsListWidget::FilteredState || list.state() == DialogsListWidget::SearchedState)) { + SearchQueries::iterator i = _searchQueries.find(req); + if (i != _searchQueries.cend()) { + _searchCache[i.value()] = result; + _searchQueries.erase(i); + } + } + 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 &msgs(result.c_messages_messages().vmessages.c_vector().v); - list.searchReceived(msgs, fromStart); + list.searchReceived(msgs, fromStart, msgs.size()); if (msgs.isEmpty()) { _searchFull = true; } @@ -1124,12 +1182,13 @@ void DialogsWidget::searchReceived(bool fromStart, const MTPmessages_Messages &r App::feedUsers(result.c_messages_messagesSlice().vusers); App::feedChats(result.c_messages_messagesSlice().vchats); const QVector &msgs(result.c_messages_messagesSlice().vmessages.c_vector().v); - list.searchReceived(msgs, fromStart); + list.searchReceived(msgs, fromStart, result.c_messages_messagesSlice().vcount.v); if (msgs.isEmpty()) { _searchFull = true; } } break; } + _searchRequest = 0; } } @@ -1167,21 +1226,15 @@ void DialogsWidget::onListScroll() { void DialogsWidget::onFilterUpdate() { 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); + if (filterText.isEmpty()) { + _searchCache.clear(); + _searchQueries.clear(); + _searchQuery = QString(); + if (!_cancelSearch.isHidden()) { + _cancelSearch.hide(); + _newGroup.show(); } - resizeEvent(0); - } - if (filterText.isEmpty() && !_cancelSearch.isHidden()) { - _cancelSearch.hide(); - _newGroup.show(); - } else if (!filterText.isEmpty() && _cancelSearch.isHidden()) { + } else if (_cancelSearch.isHidden()) { _cancelSearch.show(); _newGroup.hide(); } @@ -1190,17 +1243,11 @@ void DialogsWidget::onFilterUpdate() { 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()); _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); - } + scroll.move(0, _filter.height() + 2 * st::dlgFilterPadding); + scroll.resize(w, height() - _filter.y() - _filter.height() - st::dlgFilterPadding - st::dlgPaddingVer); list.resize(w, list.height()); onListScroll(); } @@ -1209,7 +1256,7 @@ 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) { - if (!list.choosePeer() && list.state() == DialogsListWidget::SearchedState) { + if (!list.choosePeer() && (list.state() == DialogsListWidget::SearchedState || list.state() == DialogsListWidget::FilteredState)) { onSearchMessages(); } } else if (e->key() == Qt::Key_Down) { @@ -1285,25 +1332,6 @@ void DialogsWidget::onCancelSearch() { 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()) { diff --git a/Telegram/SourceFiles/dialogswidget.h b/Telegram/SourceFiles/dialogswidget.h index 27c471a7c..2e78c200c 100644 --- a/Telegram/SourceFiles/dialogswidget.h +++ b/Telegram/SourceFiles/dialogswidget.h @@ -27,7 +27,7 @@ public: DialogsListWidget(QWidget *parent, MainWidget *main); void dialogsReceived(const QVector &dialogs); - void searchReceived(const QVector &messages, bool fromStart); + void searchReceived(const QVector &messages, bool fromStart, int32 fullCount); void showMore(int32 pixels); void activate(); @@ -119,13 +119,10 @@ private: int32 filteredSel; SearchResults searchResults; - int32 searchedSel; + int32 searchedCount, searchedSel; State _state; - QTimer _updateSearchTimer; - QString _searchQuery; - QPoint lastMousePos; void paintDialog(QPainter &p, DialogRow *dialog); @@ -191,10 +188,9 @@ public slots: void onNewGroup(); void onCancelSearch(); - void onStateChange(); - void onDialogToTopFrom(int movedFrom); - void onSearchMessages(bool force = false); + bool onSearchMessages(bool searchCache = false); + void onNeedSearchMessages(); private: @@ -213,13 +209,19 @@ private: mtpRequestId contactsRequest; FlatInput _filter; - Switcher _stateSwitcher; IconedButton _newGroup, _addContact, _cancelSearch; ScrollArea scroll; DialogsListWidget list; + QTimer _searchTimer; QString _searchQuery; bool _searchFull; mtpRequestId _searchRequest; + typedef QMap SearchCache; + SearchCache _searchCache; + + typedef QMap SearchQueries; + SearchQueries _searchQueries; + }; diff --git a/Telegram/SourceFiles/gui/text.cpp b/Telegram/SourceFiles/gui/text.cpp index f7522142b..5eb225d9f 100644 --- a/Telegram/SourceFiles/gui/text.cpp +++ b/Telegram/SourceFiles/gui/text.cpp @@ -112,7 +112,7 @@ namespace { const QRegularExpression reDomain(QString::fromUtf8("(? validProtocols, validTopDomains; void initLinkSets(); diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index c33747f83..2ca012a1e 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -1397,6 +1397,18 @@ void History::loadAround(MsgId msgId) { } } +bool History::canShowAround(MsgId msgId) const { + if (activeMsgId != msgId) { + if (msgId) { + HistoryItem *item = App::histItemById(msgId); + return item && item->block(); + } else { + return loadedAtBottom(); + } + } + return true; +} + 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) { @@ -3461,11 +3473,11 @@ void HistoryUnreadBar::setCount(int32 count) { } void HistoryUnreadBar::draw(QPainter &p, uint32 selection) const { - p.fillRect(0, 1, _history->width, st::unreadBarHeight - 2, st::unreadBarBG->b); + p.fillRect(0, st::lineWidth, _history->width, st::unreadBarHeight - 2 * st::lineWidth, st::unreadBarBG->b); p.fillRect(0, st::unreadBarHeight - st::lineWidth, _history->width, st::lineWidth, st::unreadBarBorder->b); p.setFont(st::unreadBarFont->f); p.setPen(st::unreadBarColor->p); - p.drawText(QRect(0, 0, _history->width, st::unreadBarHeight - 1), text, style::al_center); + p.drawText(QRect(0, 0, _history->width, st::unreadBarHeight - st::lineWidth), text, style::al_center); } int32 HistoryUnreadBar::resize(int32 width) { diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index b641d783e..86fa8f59d 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -610,6 +610,7 @@ struct History : public QList { void fixLastMessage(bool wasAtBottom); void loadAround(MsgId msgId); + bool canShowAround(MsgId msgId) const; MsgId minMsgId() const; MsgId maxMsgId() const; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index ebc311ec0..05c70738b 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -1455,6 +1455,8 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent) , _scroll(this, st::historyScroll, false) , _list(0) , hist(0) + , _loadingAroundId(-1) + , _loadingAroundRequest(0) , _histInited(false) , _toHistoryEnd(this, st::historyToEnd) , _send(this, lang(lng_send_button), st::btnSend) @@ -1583,29 +1585,49 @@ void HistoryWidget::chatLoaded(const MTPmessages_ChatFull &res) { peerUpdated(App::chat(peerId)); } +void HistoryWidget::clearLoadingAround() { + _loadingAroundId = -1; + if (_loadingAroundRequest) { + MTP::cancel(_loadingAroundRequest); + _loadingAroundRequest = 0; + } +} + void HistoryWidget::showPeer(const PeerId &peer, MsgId msgId, bool force, bool leaveActive) { if (App::main()->selectingPeer() && !force) { hiderOffered = true; App::main()->offerPeer(peer); return; } - if (peer) { + if (peer && !msgId) { App::main()->dialogsClear(); } if (hist) { if (histPeer->id == peer) { - if (hist->unreadBar) hist->unreadBar->destroy(); if (msgId != hist->activeMsgId) { + if (!force && !hist->canShowAround(msgId)) { + if (_loadingAroundId != msgId) { + clearLoadingAround(); + _loadingAroundId = msgId; + loadMessagesAround(); + } + return; + } hist->loadAround(msgId); if (histPreloading) MTP::cancel(histPreloading); if (histPreloadingDown) MTP::cancel(histPreloadingDown); histPreloading = histPreloadingDown = 0; } + if (hist->unreadBar) hist->unreadBar->destroy(); checkUnreadLoaded(); + + clearLoadingAround(); return activate(); } updateTyping(false); } + clearLoadingAround(); + if (_list) { if (!histPreload.isEmpty()) { _list->messagesReceived(histPreload); @@ -1852,13 +1874,15 @@ bool HistoryWidget::messagesFailed(const RPCError &e, mtpRequestId requestId) { histPreloading = 0; } else if (histPreloadingDown == requestId) { histPreloadingDown = 0; + } else if (_loadingAroundRequest == requestId) { + _loadingAroundRequest = 0; } return true; } void HistoryWidget::messagesReceived(const MTPmessages_Messages &messages, mtpRequestId requestId) { if (!hist) { - histPreloading = histPreloadingDown = 0; + histPreloading = histPreloadingDown = _loadingAroundRequest = 0; return; } @@ -1908,6 +1932,17 @@ void HistoryWidget::messagesReceived(const MTPmessages_Messages &messages, mtpRe histPreloadingDown = 0; down = true; } else { + if (_loadingAroundRequest == requestId) { + _loadingAroundRequest = 0; + hist->loadAround(_loadingAroundId); + if (hist->isEmpty()) { + addMessagesToFront(*histList); + } + if (histPreloading) MTP::cancel(histPreloading); + if (histPreloadingDown) MTP::cancel(histPreloadingDown); + histPreloading = histPreloadingDown = 0; + showPeer(hist->peer->id, _loadingAroundId, true); + } return; } @@ -2044,6 +2079,16 @@ void HistoryWidget::loadMessagesDown() { } } +void HistoryWidget::loadMessagesAround() { + if (!hist || _loadingAroundRequest || _loadingAroundId < 0) return; + + int32 offset = 0, loadCount = MessagesPerPage; + if (_loadingAroundId) { + offset = -loadCount / 2; + } + _loadingAroundRequest = MTP::send(MTPmessages_GetHistory(histInputPeer, MTP_int(offset), MTP_int(_loadingAroundId), MTP_int(loadCount)), rpcDone(&HistoryWidget::messagesReceived), rpcFail(&HistoryWidget::messagesFailed)); +} + void HistoryWidget::onListScroll() { App::checkImageCacheSize(); diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index 5e88b8b4a..95ddf393e 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -272,6 +272,7 @@ public: void loadMessages(); void loadMessagesDown(); + void loadMessagesAround(); void peerMessagesUpdated(PeerId peer); void peerMessagesUpdated(); @@ -352,6 +353,7 @@ public slots: void onPhotoReady(); void onPhotoFailed(quint64 id); void showPeer(const PeerId &peer, MsgId msgId = 0, bool force = false, bool leaveActive = false); + void clearLoadingAround(); void activate(); void onTextChange(); @@ -394,6 +396,9 @@ private: mtpRequestId histPreloading, histPreloadingDown; QVector histPreload, histPreloadDown; + int32 _loadingAroundId; + mtpRequestId _loadingAroundRequest; + ScrollArea _scroll; HistoryList *_list; History *hist; diff --git a/Telegram/SourceFiles/mtproto/mtp.cpp b/Telegram/SourceFiles/mtproto/mtp.cpp index f3d5f0052..7eaa43d5f 100644 --- a/Telegram/SourceFiles/mtproto/mtp.cpp +++ b/Telegram/SourceFiles/mtproto/mtp.cpp @@ -566,6 +566,11 @@ namespace MTP { return mtpAuthed(); } + void logoutKeys(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail) { + mtpRequestId req = MTP::send(MTPauth_LogOut(), onDone, onFail); + mtpLogoutOtherDCs(); + } + void setGlobalDoneHandler(RPCDoneHandlerPtr handler) { globalHandler.onDone = handler; } diff --git a/Telegram/SourceFiles/mtproto/mtp.h b/Telegram/SourceFiles/mtproto/mtp.h index d755cab71..d29114f3e 100644 --- a/Telegram/SourceFiles/mtproto/mtp.h +++ b/Telegram/SourceFiles/mtproto/mtp.h @@ -93,6 +93,7 @@ namespace MTP { void authed(int32 uid); int32 authedId(); + void logoutKeys(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail); void setGlobalDoneHandler(RPCDoneHandlerPtr handler); void setGlobalFailHandler(RPCFailHandlerPtr handler); diff --git a/Telegram/SourceFiles/mtproto/mtpDC.cpp b/Telegram/SourceFiles/mtproto/mtpDC.cpp index 699f74cd5..8319c27e9 100644 --- a/Telegram/SourceFiles/mtproto/mtpDC.cpp +++ b/Telegram/SourceFiles/mtproto/mtpDC.cpp @@ -323,6 +323,19 @@ int32 mtpMainDC() { return mainDC; } +void mtpLogoutOtherDCs() { + QList dcs; + { + QMutexLocker lock(&_keysMapForWriteMutex); + dcs = _keysMapForWrite.keys(); + } + for (int32 i = 0, cnt = dcs.size(); i != cnt; ++i) { + if (dcs[i] != MTP::maindc()) { + MTP::send(MTPauth_LogOut(), RPCResponseHandler(), dcs[i]); + } + } +} + void mtpSetDC(int32 dc) { if (dc != mainDC) { mainDC = dc; diff --git a/Telegram/SourceFiles/mtproto/mtpDC.h b/Telegram/SourceFiles/mtproto/mtpDC.h index 37b953514..2f937d1e1 100644 --- a/Telegram/SourceFiles/mtproto/mtpDC.h +++ b/Telegram/SourceFiles/mtproto/mtpDC.h @@ -97,6 +97,7 @@ const mtpDcOptions &mtpDCOptions(); MTProtoDCMap &mtpDCMap(); bool mtpNeedConfig(); int32 mtpMainDC(); +void mtpLogoutOtherDCs(); void mtpSetDC(int32 dc); uint32 mtpMaxChatSize(); diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj index 58da9772b..7b732cb62 100644 --- a/Telegram/Telegram.vcxproj +++ b/Telegram/Telegram.vcxproj @@ -1528,29 +1528,7 @@ - - true - true - true - - - true - true - true - - - true - true - true - - - - - true - true - true - diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters index 3ac3f30a8..474a8dde1 100644 --- a/Telegram/Telegram.vcxproj.filters +++ b/Telegram/Telegram.vcxproj.filters @@ -908,22 +908,8 @@ - - Resource Files - - - Resource Files - - - Resource Files - - - - Resource Files - -