From e45de88bd654811ca6f00a94eca3421b95130e3d Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 22 Mar 2016 22:43:47 +0300 Subject: [PATCH] moving left userpics at the top of the conversation window, beta 9034002 --- Telegram/SourceFiles/config.h | 6 +- Telegram/SourceFiles/history.cpp | 86 ++++------ Telegram/SourceFiles/history.h | 25 +-- Telegram/SourceFiles/historywidget.cpp | 220 ++++++++++++++----------- Telegram/SourceFiles/historywidget.h | 205 ++++++++++++++--------- Telegram/Telegram.rc | 8 +- Telegram/Version | 2 +- 7 files changed, 305 insertions(+), 247 deletions(-) diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index d8fdc4e3a2..b232cbb759 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org static const int32 AppVersion = 9034; static const wchar_t *AppVersionStr = L"0.9.34"; static const bool DevVersion = false; -#define BETA_VERSION (9034001ULL) // just comment this line to build public version +#define BETA_VERSION (9034002ULL) // just comment this line to build public version static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)"; static const wchar_t *AppName = L"Telegram Desktop"; @@ -101,8 +101,8 @@ enum { MediaOverviewStartPerPage = 5, MediaOverviewPreloadCount = 4, - // a new message from the same sender is attached to previous within 30 seconds - AttachMessageToPreviousSecondsDelta = 30, + // a new message from the same sender is attached to previous within 15 minutes + AttachMessageToPreviousSecondsDelta = 900, AudioVoiceMsgSimultaneously = 4, AudioSongSimultaneously = 4, diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 38406e37fa..fe436909e3 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -2843,7 +2843,7 @@ void HistoryItem::recountAttachToPrevious() { bool attach = false; if (!isPost() && !Is() && !Is()) { if (HistoryItem *prev = previous()) { - attach = !prev->isPost() && !prev->serviceMsg() && prev->from() == from()/* && qAbs(prev->date.secsTo(date)) < AttachMessageToPreviousSecondsDelta*/; + attach = !prev->isPost() && !prev->serviceMsg() && prev->from() == from() && qAbs(prev->date.secsTo(date)) < AttachMessageToPreviousSecondsDelta; } } if (attach && !(_flags & MTPDmessage_ClientFlag::f_attach_to_previous)) { @@ -2860,14 +2860,6 @@ void HistoryItem::setId(MsgId newId) { id = newId; } -bool HistoryItem::displayFromPhoto() const { - return hasFromPhoto() && !isAttachedToPrevious(); -} - -bool HistoryItem::hasFromPhoto() const { - return (Adaptive::Wide() || (!out() && !history()->peer->isUser())) && !isPost(); -} - bool HistoryItem::canEdit(const QDateTime &cur) const { ChannelData *channel = _history->peer->asChannel(); int32 s = date.secsTo(cur); @@ -6039,10 +6031,7 @@ void HistoryMessageForwarded::create(const HistoryMessageVia *via) const { HistoryMessage::HistoryMessage(History *history, const MTPDmessage &msg) : HistoryItem(history, msg.vid.v, msg.vflags.v, ::date(msg.vdate), msg.has_from_id() ? msg.vfrom_id.v : 0) -, _text(st::msgMinWidth) -, _textWidth(0) -, _textHeight(0) -, _media(0) { +, _text(st::msgMinWidth) { PeerId authorOriginalId = 0, fromOriginalId = 0; MsgId originalId = 0; if (msg.has_fwd_from() && msg.vfwd_from.type() == mtpc_messageFwdHeader) { @@ -6061,11 +6050,7 @@ HistoryMessage::HistoryMessage(History *history, const MTPDmessage &msg) : } HistoryMessage::HistoryMessage(History *history, MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *fwd) -: HistoryItem(history, id, newForwardedFlags(history->peer, from, fwd) | flags, date, from) -, _text(st::msgMinWidth) -, _textWidth(0) -, _textHeight(0) -, _media(nullptr) { +: HistoryItem(history, id, newForwardedFlags(history->peer, from, fwd) | flags, date, from) { UserData *fwdViaBot = fwd->viaBot(); int32 viaBotId = fwdViaBot ? peerToUser(fwdViaBot->id) : 0; int32 fwdViewsCount = fwd->viewsCount(), views = (fwdViewsCount > 0) ? fwdViewsCount : (isPost() ? 1 : -1); @@ -6079,22 +6064,14 @@ HistoryMessage::HistoryMessage(History *history, MsgId id, MTPDmessage::Flags fl } HistoryMessage::HistoryMessage(History *history, MsgId id, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities) - : HistoryItem(history, id, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) - , _text(st::msgMinWidth) - , _textWidth(0) - , _textHeight(0) - , _media(nullptr) { + : HistoryItem(history, id, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { createInterfaces((flags & MTPDmessage::Flag::f_via_bot_id) ? viaBotId : 0, isPost() ? 1 : -1); setText(msg, entities); } HistoryMessage::HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption) : -HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) -, _text(st::msgMinWidth) -, _textWidth(0) -, _textHeight(0) -, _media(nullptr) { +HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { createInterfaces((flags & MTPDmessage::Flag::f_via_bot_id) ? viaBotId : 0, isPost() ? 1 : -1); initMediaFromDocument(doc, caption); @@ -6102,11 +6079,7 @@ HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) } HistoryMessage::HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption) : -HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) -, _text(st::msgMinWidth) -, _textWidth(0) -, _textHeight(0) -, _media(nullptr) { +HistoryItem(history, msgId, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { createInterfaces((flags & MTPDmessage::Flag::f_via_bot_id) ? viaBotId : 0, isPost() ? 1 : -1); _media = new HistoryPhoto(photo, caption, this); @@ -6598,14 +6571,11 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m textstyleSet(&(outbg ? st::outTextStyle : st::inTextStyle)); - if (displayFromPhoto()) { - int photoleft = left + ((outbg && !Adaptive::Wide()) ? (width + (st::msgPhotoSkip - st::msgPhotoSize)) : (-st::msgPhotoSkip)); - int phototop = marginTop(); -// if (history()->scrollTopItem == this) { -// phototop = qMax(qMin(history()->scrollTopOffset, _height - marginBottom() - int(st::msgPhotoSize)), phototop); -// } - author()->paintUserpic(p, st::msgPhotoSize, photoleft, phototop); - } + //if (displayFromPhoto()) { + // int photoleft = left + ((outbg && !Adaptive::Wide()) ? (width + (st::msgPhotoSkip - st::msgPhotoSize)) : (-st::msgPhotoSkip)); + // int phototop = marginTop(); + // author()->paintUserpic(p, st::msgPhotoSize, photoleft, phototop); + //} if (bubble) { const HistoryMessageForwarded *fwd = Get(); @@ -6809,13 +6779,13 @@ void HistoryMessage::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 int left = 0, width = 0, height = _height; countPositionAndSize(left, width); - if (displayFromPhoto()) { - int32 photoleft = left + ((!isPost() && out() && !Adaptive::Wide()) ? (width + (st::msgPhotoSkip - st::msgPhotoSize)) : (-st::msgPhotoSkip)); - if (x >= photoleft && x < photoleft + st::msgPhotoSize && y >= marginTop() && y < height - marginBottom()) { - lnk = author()->lnk; - return; - } - } + //if (displayFromPhoto()) { + // int32 photoleft = left + ((!isPost() && out() && !Adaptive::Wide()) ? (width + (st::msgPhotoSkip - st::msgPhotoSize)) : (-st::msgPhotoSkip)); + // if (x >= photoleft && x < photoleft + st::msgPhotoSize && y >= marginTop() && y < height - marginBottom()) { + // lnk = author()->lnk; + // return; + // } + //} if (width < 1) return; if (drawBubble()) { @@ -6972,6 +6942,14 @@ QString HistoryMessage::notificationText() const { return msg; } +bool HistoryMessage::displayFromPhoto() const { + return hasFromPhoto() && !isAttachedToPrevious(); +} + +bool HistoryMessage::hasFromPhoto() const { + return (Adaptive::Wide() || (!out() && !history()->peer->isUser())) && !isPost(); +} + HistoryMessage::~HistoryMessage() { if (_media) { _media->detachFromItem(this); @@ -7224,12 +7202,12 @@ void HistoryReply::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x if (drawBubble()) { int32 left = 0, width = 0; countPositionAndSize(left, width); - if (displayFromPhoto()) { - int32 photoleft = left + ((!isPost() && out()) ? (width + (st::msgPhotoSkip - st::msgPhotoSize)) : (-st::msgPhotoSkip)); - if (x >= photoleft && x < photoleft + st::msgPhotoSize) { - return HistoryMessage::getState(lnk, state, x, y); - } - } + //if (displayFromPhoto()) { + // int32 photoleft = left + ((!isPost() && out()) ? (width + (st::msgPhotoSkip - st::msgPhotoSize)) : (-st::msgPhotoSkip)); + // if (x >= photoleft && x < photoleft + st::msgPhotoSize) { + // return HistoryMessage::getState(lnk, state, x, y); + // } + //} if (width < 1) return; int top = marginTop(); diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 99eb6b22cb..5520aeccd5 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -1384,6 +1384,9 @@ public: int marginBottom() const { return st::msgMargin.bottom(); } + bool isAttachedToPrevious() const { + return _flags & MTPDmessage_ClientFlag::f_attach_to_previous; + } void clipCallback(ClipReaderNotification notification); @@ -1434,14 +1437,6 @@ protected: // HistoryMessageDate or HistoryMessageUnreadBar bit is changed in the Interfaces mask // then the result should be cached in a client side flag MTPDmessage_ClientFlag::f_attach_to_previous void recountAttachToPrevious(); - bool isAttachedToPrevious() const { - return _flags & MTPDmessage_ClientFlag::f_attach_to_previous; - } - - // hasFromPhoto() returns true even if we don't display the photo - // but we need to skip a place at the left side for this photo - bool displayFromPhoto() const; - bool hasFromPhoto() const; }; @@ -2495,6 +2490,11 @@ public: return this; } + // hasFromPhoto() returns true even if we don't display the photo + // but we need to skip a place at the left side for this photo + bool displayFromPhoto() const; + bool hasFromPhoto() const; + ~HistoryMessage(); protected: @@ -2519,13 +2519,14 @@ protected: } void paintForwardedInfo(Painter &p, int32 x, int32 y, int32 w, bool selected) const; - Text _text; + Text _text = { st::msgMinWidth }; - int32 _textWidth, _textHeight; + int _textWidth = 0; + int _textHeight = 0; - HistoryMedia *_media; + HistoryMedia *_media = nullptr; QString _timeText; - int32 _timeWidth; + int _timeWidth = 0; }; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 28980fec1d..61a2557c0b 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -38,41 +38,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org // flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html -HistoryInner::HistoryInner(HistoryWidget *historyWidget, ScrollArea *scroll, History *history) : TWidget(0) +HistoryInner::HistoryInner(HistoryWidget *historyWidget, ScrollArea *scroll, History *history) : TWidget(nullptr) , _peer(history->peer) -, _migrated(history->peer->migrateFrom() ? App::history(history->peer->migrateFrom()->id) : 0) +, _migrated(history->peer->migrateFrom() ? App::history(history->peer->migrateFrom()->id) : nullptr) , _history(history) -, _historyOffset(0) -, _historySkipHeight(0) -, _botInfo(history->peer->isUser() ? history->peer->asUser()->botInfo : 0) -, _botDescWidth(0) -, _botDescHeight(0) +, _botInfo(history->peer->isUser() ? history->peer->asUser()->botInfo : nullptr) , _widget(historyWidget) -, _scroll(scroll) -, _curHistory(0) -, _curBlock(0) -, _curItem(0) -, _firstLoading(false) -, _cursor(style::cur_default) -, _dragAction(NoDrag) -, _dragSelType(TextSelectLetters) -, _dragItem(0) -, _dragCursorState(HistoryDefaultCursorState) -, _dragWasInactive(false) -, _dragSelFrom(0) -, _dragSelTo(0) -, _dragSelecting(false) -, _wasSelectedText(false) -, _touchScroll(false) -, _touchSelect(false) -, _touchInProgress(false) -, _touchScrollState(TouchScrollManual) -, _touchPrevPosValid(false) -, _touchWaitingAcceleration(false) -, _touchSpeedTime(0) -, _touchAccelerationTime(0) -, _touchTime(0) -, _menu(0) { +, _scroll(scroll) { connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); _touchSelectTimer.setSingleShot(true); @@ -122,6 +94,69 @@ void HistoryInner::repaintItem(const HistoryItem *item) { } } +template +void HistoryInner::enumerateUserpicsInHistory(History *h, int htop, Method method) { + // no displayed messages in this history + if (htop < 0) return; + + // find and remember the bottom of an attached messages pack + // -1 means we didn't find an attached to previous message yet + int lowestAttachedItemBottom = -1; + + int blockIndex = h->blocks.size(); + int itemIndex = 0; + while (blockIndex > 0) { + HistoryBlock *block = h->blocks.at(--blockIndex); + itemIndex = block->items.size(); + + int blocktop = htop + block->y; + while (itemIndex > 0) { + HistoryItem *item = block->items.at(--itemIndex); + int itemtop = blocktop + item->y; + int itembottom = itemtop + item->height(); + + // skip items that are below the visible area + if (itemtop >= _visibleAreaBottom) { + continue; + } + + if (HistoryMessage *message = item->toHistoryMessage()) { + if (lowestAttachedItemBottom < 0 && message->isAttachedToPrevious()) { + lowestAttachedItemBottom = itembottom - message->marginBottom(); + } + + // draw userpic for all messages that have it and for those who are not showing it + // because of their attachment to the previous message if they are top-most visible + if (message->displayFromPhoto() || (message->hasFromPhoto() && itemtop <= _visibleAreaTop)) { + if (lowestAttachedItemBottom < 0) { + lowestAttachedItemBottom = itembottom - message->marginBottom(); + } + int userpicTop = qMin(qMax(itemtop + message->marginTop(), _visibleAreaTop + st::msgMargin.left()), lowestAttachedItemBottom - int(st::msgPhotoSize)); + + // call the template callback function that was passed + // and return if it finished everything it needed + if (!method(message, userpicTop)) { + return; + } + + // forget the found bottom of the pack, search for the next one from scratch + lowestAttachedItemBottom = -1; + } + } + + // skip all the items that are above the visible area + if (itemtop <= _visibleAreaTop) { + return; + } + } + + // skip all the rest blocks that are above the visible area + if (blocktop <= _visibleAreaTop) { + return; + } + } +} + void HistoryInner::paintEvent(QPaintEvent *e) { if (App::wnd() && App::wnd()->contentOverlapped(this, e)) return; @@ -252,6 +287,19 @@ void HistoryInner::paintEvent(QPaintEvent *e) { item = block->items[iItem]; } p.restore(); + + enumerateUserpics([&p, &r](HistoryMessage *message, int userpicTop) -> bool { + // stop the enumeration if the userpic is above the painted rect + if (userpicTop + st::msgPhotoSize <= r.top()) { + return false; + } + + // paint the userpic if it intersects the painted rect + if (userpicTop < r.top() + r.height()) { + message->from()->paintUserpicLeft(p, st::msgPhotoSize, st::msgMargin.left(), userpicTop, message->history()->width); + } + return true; + }); } } } @@ -1360,6 +1408,7 @@ HistoryItem *HistoryInner::atTopImportantMsg(int32 top, int32 height, int32 &bot void HistoryInner::visibleAreaUpdated(int top, int bottom) { _visibleAreaTop = top; + _visibleAreaBottom = bottom; // if history has pending resize events we should not update scrollTopItem if (_history->hasPendingResizedItems()) { @@ -1637,6 +1686,25 @@ void HistoryInner::onUpdateSelected() { } } else if (item) { item->getState(lnk, cursorState, m.x(), m.y()); + if (!lnk && m.x() >= st::msgMargin.left() && m.x() < st::msgMargin.left() + st::msgPhotoSize) { + if (HistoryMessage *msg = item->toHistoryMessage()) { + if (msg->hasFromPhoto()) { + enumerateUserpics([&lnk, msg, &point](HistoryMessage *message, int userpicTop) -> bool { + // stop enumeration if the userpic is above our point + if (userpicTop + st::msgPhotoSize <= point.y()) { + return false; + } + + // stop enumeration if we've found a userpic under the cursor + if (point.y() >= userpicTop && point.y() < userpicTop + st::msgPhotoSize) { + lnk = message->from()->lnk; + return false; + } + return true; + }); + } + } + } } if (lnk != textlnkOver()) { lnkChanged = true; @@ -2690,52 +2758,17 @@ QPoint SilentToggle::tooltipPos() const { } HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) -, _replyToId(0) -, _replyToNameVersion(0) -, _editMsgId(0) -, _replyEditMsg(0) , _fieldBarCancel(this, st::replyCancel) -, _pinnedBar(0) -, _saveEditMsgRequestId(0) -, _reportSpamStatus(dbiprsUnknown) -, _reportSpamSettingRequestId(ReportSpamRequestNeeded) -, _previewData(0) -, _previewRequest(0) -, _previewCancelled(false) -, _replyForwardPressed(false) -, _replyReturn(0) -, _stickersUpdateRequest(0) -, _savedGifsUpdateRequest(0) -, _peer(0) -, _clearPeer(0) -, _channel(NoChannel) -, _showAtMsgId(0) -, _fixedInScrollMsgId(0) -, _fixedInScrollMsgTop(0) -, _firstLoadRequest(0), _preloadRequest(0), _preloadDownRequest(0) -, _delayedShowAtMsgId(-1) -, _delayedShowAtRequest(0) -, _activeAnimMsgId(0) , _scroll(this, st::historyScroll, false) -, _list(0) -, _migrated(0) -, _history(0) -, _histInited(false) -, _lastScroll(0) -, _lastScrolled(0) , _toHistoryEnd(this, st::historyToEnd) , _collapseComments(this) , _attachMention(this) -, _inlineBot(0) -, _inlineBotResolveRequestId(0) , _reportSpamPanel(this) , _send(this, lang(lng_send_button), st::btnSend) , _unblock(this, lang(lng_unblock_button), st::btnUnblock) , _botStart(this, lang(lng_bot_start), st::btnSend) , _joinChannel(this, lang(lng_channel_join), st::btnSend) , _muteUnmute(this, lang(lng_channel_mute), st::btnSend) -, _unblockRequest(0) -, _reportSpamRequest(0) , _attachDocument(this, st::btnAttachDocument) , _attachPhoto(this, st::btnAttachPhoto) , _attachEmoji(this, st::btnAttachEmoji) @@ -2744,42 +2777,20 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) , _cmdStart(this, st::btnBotCmdStart) , _broadcast(this, QString(), true, st::broadcastToggle) , _silent(this) -, _cmdStartShown(false) , _field(this, st::taMsgField, lang(lng_message_ph)) , _a_record(animation(this, &HistoryWidget::step_record)) , _a_recording(animation(this, &HistoryWidget::step_recording)) -, _recording(false) -, _inRecord(false) -, _inField(false) -, _inReplyEdit(false) -, _inPinnedMsg(false) -, a_recordingLevel(0, 0) -, _recordingSamples(0) -, a_recordOver(0, 0) -, a_recordDown(0, 0) , a_recordCancel(st::recordCancel->c, st::recordCancel->c) , _recordCancelWidth(st::recordFont->width(lang(lng_record_cancel))) -, _kbShown(false) -, _kbReplyTo(0) , _kbScroll(this, st::botKbScroll) -, _keyboard() , _attachType(this) , _emojiPan(this) -, _attachDrag(DragStateNone) , _attachDragDocument(this) , _attachDragPhoto(this) , _fileLoader(this, FileLoaderQueueStopTimeout) -, _textUpdateEventsFlags(TextUpdateEventsSaveDraft | TextUpdateEventsSendTyping) -, _serviceImageCacheSize(0) -, _confirmWithTextId(0) -, _titlePeerTextWidth(0) , _a_show(animation(this, &HistoryWidget::step_show)) -, _scrollDelta(0) -, _saveDraftStart(0) -, _saveDraftText(false) , _sideShadow(this, st::shadowColor) -, _topShadow(this, st::shadowColor) -, _inGrab(false) { +, _topShadow(this, st::shadowColor) { _scroll.setFocusPolicy(Qt::NoFocus); setAcceptDrops(true); @@ -3658,7 +3669,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re _fieldBarCancel.hide(); if (_list) _list->deleteLater(); - _list = 0; + _list = nullptr; _scroll.takeWidget(); updateTopBarSelection(); @@ -3730,6 +3741,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re _scroll.hide(); _scroll.setWidget(_list); _list->show(); + visibleAreaUpdated(); _updateHistoryItems.stop(); @@ -3965,9 +3977,9 @@ void HistoryWidget::updateControlsVisibility() { _pinnedBar->cancel.show(); _pinnedBar->shadow.show(); } - if (_firstLoadRequest) { + if (_firstLoadRequest && !_scroll.isHidden()) { _scroll.hide(); - } else { + } else if (!_firstLoadRequest && _scroll.isHidden()) { _scroll.show(); } if (_reportSpamStatus == dbiprsShowButton || _reportSpamStatus == dbiprsReportSent) { @@ -4578,7 +4590,10 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) { void HistoryWidget::onScroll() { App::checkImageCacheSize(); preloadHistoryIfNeeded(); + visibleAreaUpdated(); +} +void HistoryWidget::visibleAreaUpdated() { if (_list && !_scroll.isHidden()) { int st = _scroll.scrollTop(); _list->visibleAreaUpdated(st, st + _scroll.height()); @@ -6385,6 +6400,8 @@ void HistoryWidget::updateListSize(bool initial, bool loadedDown, const ScrollCh bool wasAtBottom = _scroll.scrollTop() + 1 > _scroll.scrollTopMax(), needResize = _scroll.width() != width() || _scroll.height() != newScrollHeight; if (needResize) { _scroll.resize(width(), newScrollHeight); + visibleAreaUpdated(); + _attachMention.setBoundings(_scroll.geometry()); _toHistoryEnd.move((width() - _toHistoryEnd.width()) / 2, _scroll.y() + _scroll.height() - _toHistoryEnd.height() - st::historyToEndSkip); updateCollapseCommentsVisibility(); @@ -6402,13 +6419,19 @@ void HistoryWidget::updateListSize(bool initial, bool loadedDown, const ScrollCh } if ((!initial && !wasAtBottom) || (loadedDown && (!_history->showFrom || _history->unreadBar || _history->loadedAtBottom()) && (!_migrated || !_migrated->showFrom || _migrated->unreadBar || _history->loadedAtBottom()))) { - int32 addToY = 0; + int addToY = 0; if (change.type == ScrollChangeAdd) { addToY = change.value; } else if (change.type == ScrollChangeOldHistoryHeight) { addToY = _list->historyHeight() - change.value; } - _scroll.scrollToY(_list->historyScrollTop() + addToY); + int toY = _list->historyScrollTop() + addToY; + if (toY > _scroll.scrollTopMax()) toY = _scroll.scrollTopMax(); + if (_scroll.scrollTop() == toY) { + visibleAreaUpdated(); + } else { + _scroll.scrollToY(toY); + } return; } @@ -6511,7 +6534,12 @@ void HistoryWidget::updateListSize(bool initial, bool loadedDown, const ScrollCh } } else { } - _scroll.scrollToY(toY); + if (toY > _scroll.scrollTopMax()) toY = _scroll.scrollTopMax(); + if (_scroll.scrollTop() == toY) { + visibleAreaUpdated(); + } else { + _scroll.scrollToY(toY); + } } void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector &messages, const QVector *collapsed) { diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index 7c7ba35b91..5eabc4ffb9 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -139,22 +139,30 @@ private: HistoryItem *nextItem(HistoryItem *item); void updateDragSelection(HistoryItem *dragSelFrom, HistoryItem *dragSelTo, bool dragSelecting, bool force = false); - PeerData *_peer; - History *_migrated, *_history; - int32 _historyOffset, _historySkipHeight; // height of first date and first sys msg + PeerData *_peer = nullptr; + History *_migrated = nullptr; + History *_history = nullptr; + int _historyOffset = 0; - BotInfo *_botInfo; - int32 _botDescWidth, _botDescHeight; + // with migrated history we perhaps do not need to display first _history message + // (if last _migrated message and first _history message are both isGroupMigrate) + // or at least we don't need to display first _history date (just skip it by height) + int _historySkipHeight = 0; + + BotInfo *_botInfo = nullptr; + int _botDescWidth = 0; + int _botDescHeight = 0; QRect _botDescRect; - HistoryWidget *_widget; - ScrollArea *_scroll; - mutable History *_curHistory; - mutable int32 _curBlock, _curItem; + HistoryWidget *_widget = nullptr; + ScrollArea *_scroll = nullptr; + mutable History *_curHistory = nullptr; + mutable int _curBlock = 0; + mutable int _curItem = 0; - bool _firstLoading; + bool _firstLoading = false; - Qt::CursorShape _cursor; + style::cursor _cursor = style::cur_default; typedef QMap SelectedItems; SelectedItems _selected; void applyDragSelection(); @@ -168,36 +176,60 @@ private: PrepareSelect = 0x03, Selecting = 0x04, }; - DragAction _dragAction; - TextSelectType _dragSelType; + DragAction _dragAction = NoDrag; + TextSelectType _dragSelType = TextSelectLetters; QPoint _dragStartPos, _dragPos; - HistoryItem *_dragItem; - HistoryCursorState _dragCursorState; - uint16 _dragSymbol; - bool _dragWasInactive; + HistoryItem *_dragItem = nullptr; + HistoryCursorState _dragCursorState = HistoryDefaultCursorState; + uint16 _dragSymbol = 0; + bool _dragWasInactive = false; QPoint _trippleClickPoint; QTimer _trippleClickTimer; TextLinkPtr _contextMenuLnk; - HistoryItem *_dragSelFrom, *_dragSelTo; - bool _dragSelecting; - bool _wasSelectedText; // was some text selected in current drag action + HistoryItem *_dragSelFrom = nullptr; + HistoryItem *_dragSelTo = nullptr; + bool _dragSelecting = false; + bool _wasSelectedText = false; // was some text selected in current drag action - bool _touchScroll, _touchSelect, _touchInProgress; + // scroll by touch support (at least Windows Surface tablets) + bool _touchScroll = false; + bool _touchSelect = false; + bool _touchInProgress = false; QPoint _touchStart, _touchPrevPos, _touchPos; QTimer _touchSelectTimer; - TouchScrollState _touchScrollState; - bool _touchPrevPosValid, _touchWaitingAcceleration; + TouchScrollState _touchScrollState = TouchScrollManual; + bool _touchPrevPosValid = false; + bool _touchWaitingAcceleration = false; QPoint _touchSpeed; - uint64 _touchSpeedTime, _touchAccelerationTime, _touchTime; + uint64 _touchSpeedTime = 0; + uint64 _touchAccelerationTime = 0; + uint64 _touchTime = 0; QTimer _touchScrollTimer; - PopupMenu *_menu; + // context menu + PopupMenu *_menu = nullptr; + // save visible area coords for painting / pressing userpics int _visibleAreaTop = 0; + int _visibleAreaBottom = 0; + + // this function finds all userpics on the left that are displayed and calls template method + // for each found userpic (from the bottom to the top) in the passed history with passed top offset + // + // method has "bool (*Method)(HistoryMessage *message, int userpicTop)" signature + // if it returns false the enumeration stops immidiately + template + void enumerateUserpicsInHistory(History *h, int htop, Method method); + + template + void enumerateUserpics(Method method) { + enumerateUserpicsInHistory(_history, historyTop(), method); + enumerateUserpicsInHistory(_migrated, migratedTop(), method); + } }; @@ -721,14 +753,14 @@ public slots: private: - MsgId _replyToId; + MsgId _replyToId = 0; Text _replyToName; - int32 _replyToNameVersion; + int _replyToNameVersion = 0; void updateReplyToName(); - MsgId _editMsgId; + MsgId _editMsgId = 0; - HistoryItem *_replyEditMsg; + HistoryItem *_replyEditMsg = nullptr; Text _replyEditMsgText; IconedButton _fieldBarCancel; @@ -737,13 +769,13 @@ private: struct PinnedBar { PinnedBar(MsgId msgId, HistoryWidget *parent); - MsgId msgId; - HistoryItem *msg; + MsgId msgId = 0; + HistoryItem *msg = nullptr; Text text; IconedButton cancel; PlainShadow shadow; }; - PinnedBar *_pinnedBar; + PinnedBar *_pinnedBar = nullptr; void updatePinnedBar(bool force = false); bool pinnedMsgVisibilityUpdated(); void destroyPinnedBar(); @@ -767,32 +799,33 @@ private: // destroys _history and _migrated unread bars void destroyUnreadBar(); - mtpRequestId _saveEditMsgRequestId; + mtpRequestId _saveEditMsgRequestId = 0; void saveEditMsg(); void saveEditMsgDone(History *history, const MTPUpdates &updates, mtpRequestId req); bool saveEditMsgFail(History *history, const RPCError &error, mtpRequestId req); - DBIPeerReportSpamStatus _reportSpamStatus; - mtpRequestId _reportSpamSettingRequestId; static const mtpRequestId ReportSpamRequestNeeded = -1; + DBIPeerReportSpamStatus _reportSpamStatus = dbiprsUnknown; + mtpRequestId _reportSpamSettingRequestId = ReportSpamRequestNeeded; void updateReportSpamStatus(); void requestReportSpamSetting(); void reportSpamSettingDone(const MTPPeerSettings &result, mtpRequestId req); bool reportSpamSettingFail(const RPCError &error, mtpRequestId req); QString _previewLinks; - WebPageData *_previewData; + WebPageData *_previewData = nullptr; typedef QMap PreviewCache; PreviewCache _previewCache; - mtpRequestId _previewRequest; - Text _previewTitle, _previewDescription; + mtpRequestId _previewRequest = 0; + Text _previewTitle; + Text _previewDescription; SingleTimer _previewTimer; - bool _previewCancelled; + bool _previewCancelled = false; void gotPreview(QString links, const MTPMessageMedia &media, mtpRequestId req); - bool _replyForwardPressed; + bool _replyForwardPressed = false; - HistoryItem *_replyReturn; + HistoryItem *_replyReturn = nullptr; QList _replyReturns; bool messagesFailed(const RPCError &error, mtpRequestId requestId); @@ -824,11 +857,11 @@ private: void countHistoryShowFrom(); - mtpRequestId _stickersUpdateRequest; + mtpRequestId _stickersUpdateRequest = 0; void stickersGot(const MTPmessages_AllStickers &stickers); bool stickersFailed(const RPCError &error); - mtpRequestId _savedGifsUpdateRequest; + mtpRequestId _savedGifsUpdateRequest = 0; void savedGifsGot(const MTPmessages_SavedGifs &gifs); bool savedGifsFailed(const RPCError &error); @@ -840,39 +873,51 @@ private: void updateDragAreas(); + // when scroll position or scroll area size changed this method + // updates the boundings of the visible area in HistoryInner + void visibleAreaUpdated(); + bool readyToForward() const; bool hasBroadcastToggle() const; bool hasSilentToggle() const; - PeerData *_peer, *_clearPeer; // cache _peer in _clearPeer when showing clear history box - ChannelId _channel; - bool _canSendMessages; - MsgId _showAtMsgId, _fixedInScrollMsgId; - int32 _fixedInScrollMsgTop; + PeerData *_peer = nullptr; - mtpRequestId _firstLoadRequest, _preloadRequest, _preloadDownRequest; + // cache current _peer in _clearPeer when showing clear history box + PeerData *_clearPeer = nullptr; - MsgId _delayedShowAtMsgId; - mtpRequestId _delayedShowAtRequest; + ChannelId _channel = NoChannel; + bool _canSendMessages = false; + MsgId _showAtMsgId = ShowAtUnreadMsgId; + MsgId _fixedInScrollMsgId = 0; + int32 _fixedInScrollMsgTop = 0; - MsgId _activeAnimMsgId; + mtpRequestId _firstLoadRequest = 0; + mtpRequestId _preloadRequest = 0; + mtpRequestId _preloadDownRequest = 0; + + MsgId _delayedShowAtMsgId = -1; // wtf? + mtpRequestId _delayedShowAtRequest = 0; + + MsgId _activeAnimMsgId = 0; ScrollArea _scroll; - HistoryInner *_list; - History *_migrated, *_history; - bool _histInited; // initial updateListSize() called + HistoryInner *_list = nullptr; + History *_migrated = nullptr; + History *_history = nullptr; + bool _histInited = false; // initial updateListSize() called - int32 _lastScroll; - uint64 _lastScrolled; + int32 _lastScroll = 0; + uint64 _lastScrolled = 0; QTimer _updateHistoryItems; // gifs optimization IconedButton _toHistoryEnd; CollapseButton _collapseComments; MentionsDropdown _attachMention; - UserData *_inlineBot; + UserData *_inlineBot = nullptr; QString _inlineBotUsername; - mtpRequestId _inlineBotResolveRequestId; + mtpRequestId _inlineBotResolveRequestId = 0; void inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result); bool inlineBotResolveFail(QString name, const RPCError &error); @@ -885,46 +930,52 @@ private: ReportSpamPanel _reportSpamPanel; FlatButton _send, _unblock, _botStart, _joinChannel, _muteUnmute; - mtpRequestId _unblockRequest, _reportSpamRequest; + mtpRequestId _unblockRequest = 0; + mtpRequestId _reportSpamRequest = 0; IconedButton _attachDocument, _attachPhoto; EmojiButton _attachEmoji; IconedButton _kbShow, _kbHide, _cmdStart; FlatCheckbox _broadcast; SilentToggle _silent; - bool _cmdStartShown; + bool _cmdStartShown = false; MessageField _field; Animation _a_record, _a_recording; - bool _recording, _inRecord, _inField, _inReplyEdit, _inPinnedMsg; - anim::ivalue a_recordingLevel; - int32 _recordingSamples; - anim::fvalue a_recordOver, a_recordDown; + bool _recording = false; + bool _inRecord = false; + bool _inField = false; + bool _inReplyEdit = false; + bool _inPinnedMsg = false; + anim::ivalue a_recordingLevel = { 0, 0 }; + int32 _recordingSamples = 0; + anim::fvalue a_recordOver = { 0, 0 }; + anim::fvalue a_recordDown = { 0, 0 }; anim::cvalue a_recordCancel; int32 _recordCancelWidth; bool kbWasHidden() const; - bool _kbShown; - HistoryItem *_kbReplyTo; + bool _kbShown = false; + HistoryItem *_kbReplyTo = nullptr; ScrollArea _kbScroll; BotKeyboard _keyboard; Dropdown _attachType; EmojiPan _emojiPan; - DragState _attachDrag; + DragState _attachDrag = DragStateNone; DragArea _attachDragDocument, _attachDragPhoto; int32 _selCount; // < 0 - text selected, focus list, not _field TaskQueue _fileLoader; - int32 _textUpdateEventsFlags; + int32 _textUpdateEventsFlags = (TextUpdateEventsSaveDraft | TextUpdateEventsSendTyping); - int64 _serviceImageCacheSize; + int64 _serviceImageCacheSize = 0; QString _confirmSource; - uint64 _confirmWithTextId; + uint64 _confirmWithTextId = 0; QString _titlePeerText; - int32 _titlePeerTextWidth; + int32 _titlePeerTextWidth = 0; Animation _a_show; QPixmap _cacheUnder, _cacheOver, _cacheTopBarUnder, _cacheTopBarOver; @@ -932,20 +983,20 @@ private: anim::fvalue a_shadow; QTimer _scrollTimer; - int32 _scrollDelta; + int32 _scrollDelta = 0; QTimer _animActiveTimer; - float64 _animActiveStart; + float64 _animActiveStart = 0; QMap, mtpRequestId> _sendActionRequests; QTimer _sendActionStopTimer; - uint64 _saveDraftStart; - bool _saveDraftText; + uint64 _saveDraftStart = 0; + bool _saveDraftText = false; QTimer _saveDraftTimer; PlainShadow _sideShadow, _topShadow; - bool _inGrab; + bool _inGrab = false; }; diff --git a/Telegram/Telegram.rc b/Telegram/Telegram.rc index debef465de..8485fe9cd2 100644 --- a/Telegram/Telegram.rc +++ b/Telegram/Telegram.rc @@ -34,8 +34,8 @@ IDI_ICON1 ICON "SourceFiles\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,9,34,1 - PRODUCTVERSION 0,9,34,1 + FILEVERSION 0,9,34,2 + PRODUCTVERSION 0,9,34,2 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Telegram Messenger LLP" - VALUE "FileVersion", "0.9.34.1" + VALUE "FileVersion", "0.9.34.2" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.9.34.1" + VALUE "ProductVersion", "0.9.34.2" END END BLOCK "VarFileInfo" diff --git a/Telegram/Version b/Telegram/Version index 106da55f5b..1997f59694 100644 --- a/Telegram/Version +++ b/Telegram/Version @@ -3,4 +3,4 @@ AppVersionStrMajor 0.9 AppVersionStrSmall 0.9.34 AppVersionStr 0.9.34 DevChannel 0 -BetaVersion 9034001 +BetaVersion 9034002