mirror of https://github.com/procxx/kepka.git
				
				
				
			Fix crash and improve animated scrolling.
Also fix reply returns traversing after animated scrolling.
This commit is contained in:
		
							parent
							
								
									e0978f86d1
								
							
						
					
					
						commit
						9665d5cb45
					
				|  | @ -676,12 +676,30 @@ void HistoryWidget::scrollToCurrentVoiceMessage(FullMsgId fromId, FullMsgId toId | ||||||
| void HistoryWidget::animatedScrollToItem(MsgId msgId) { | void HistoryWidget::animatedScrollToItem(MsgId msgId) { | ||||||
| 	Expects(_history != nullptr); | 	Expects(_history != nullptr); | ||||||
| 
 | 
 | ||||||
| 	auto animatedScrollAttachedToItem = [this](HistoryItem *item, int scrollTo) { | 	auto to = App::histItemById(_channel, msgId); | ||||||
| 		auto itemTop = _list->itemTop(item); | 	if (_list->itemTop(to) < 0) { | ||||||
| 		if (itemTop < 0) { | 		return; | ||||||
| 			return false; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	auto scrollTo = snap(itemTopForHighlight(to), 0, _scroll->scrollTopMax()); | ||||||
|  | 	animatedScrollToY(scrollTo, to); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void HistoryWidget::animatedScrollToY(int scrollTo, HistoryItem *attachTo) { | ||||||
|  | 	Expects(_history != nullptr); | ||||||
|  | 
 | ||||||
|  | 	// Attach our scroll animation to some item.
 | ||||||
|  | 	auto itemTop = _list->itemTop(attachTo); | ||||||
|  | 	if (itemTop < 0 && !_history->isEmpty()) { | ||||||
|  | 		attachTo = _history->blocks.back()->items.back(); | ||||||
|  | 		itemTop = _list->itemTop(attachTo); | ||||||
|  | 	} | ||||||
|  | 	if (itemTop < 0) { | ||||||
|  | 		synteticScrollToY(scrollTo); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	_scrollToAnimation.finish(); | ||||||
| 	auto maxAnimatedDelta = _scroll->height(); | 	auto maxAnimatedDelta = _scroll->height(); | ||||||
| 	auto transition = anim::sineInOut; | 	auto transition = anim::sineInOut; | ||||||
| 	auto scrollTop = _scroll->scrollTop(); | 	auto scrollTop = _scroll->scrollTop(); | ||||||
|  | @ -694,36 +712,20 @@ void HistoryWidget::animatedScrollToItem(MsgId msgId) { | ||||||
| 		synteticScrollToY(scrollTop); | 		synteticScrollToY(scrollTop); | ||||||
| 		transition = anim::easeOutCubic; | 		transition = anim::easeOutCubic; | ||||||
| 	} | 	} | ||||||
| 		_scrollToMediaMessageAnimation.finish(); | 	_scrollToAnimation.start([this, itemId = attachTo->fullId()] { scrollToAnimationCallback(itemId); }, scrollTop - itemTop, scrollTo - itemTop, st::slideDuration, anim::sineInOut); | ||||||
| 		_scrollToMediaMessageAnimation.start([this, itemId = item->fullId()] { | } | ||||||
| 			auto itemTop = _list->itemTop(App::histItemById(itemId)); | 
 | ||||||
|  | void HistoryWidget::scrollToAnimationCallback(FullMsgId attachToId) { | ||||||
|  | 	auto itemTop = _list->itemTop(App::histItemById(attachToId)); | ||||||
| 	if (itemTop < 0) { | 	if (itemTop < 0) { | ||||||
| 				_scrollToMediaMessageAnimation.finish(); | 		_scrollToAnimation.finish(); | ||||||
| 	} else { | 	} else { | ||||||
| 				synteticScrollToY(qRound(_scrollToMediaMessageAnimation.current()) + itemTop); | 		synteticScrollToY(qRound(_scrollToAnimation.current()) + itemTop); | ||||||
| 	} | 	} | ||||||
| 		}, scrollTop - itemTop, scrollTo - itemTop, st::slideDuration, anim::sineInOut); | 	if (!_scrollToAnimation.animating()) { | ||||||
| 		return true; | 		preloadHistoryByScroll(); | ||||||
| 	}; | 		checkReplyReturns(); | ||||||
| 
 |  | ||||||
| 	if (msgId == ShowAtUnreadMsgId) { |  | ||||||
| 		// Special case "scroll to bottom".
 |  | ||||||
| 		auto scrollTo = _scroll->scrollTopMax(); |  | ||||||
| 
 |  | ||||||
| 		// Attach our scroll animation to some item.
 |  | ||||||
| 		auto item = _history->isEmpty() ? nullptr : _history->blocks.back()->items.back(); |  | ||||||
| 		if (animatedScrollAttachedToItem(item, scrollTo)) { |  | ||||||
| 			return; |  | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 		// If something went wrong we just scroll without animation.
 |  | ||||||
| 		synteticScrollToY(scrollTo); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	auto to = App::histItemById(_channel, msgId); |  | ||||||
| 	auto scrollTo = snap(itemTopForHighlight(to), 0, _scroll->scrollTopMax()); |  | ||||||
| 	animatedScrollAttachedToItem(to, scrollTo); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void HistoryWidget::highlightMessage(HistoryItem *context) { | void HistoryWidget::highlightMessage(HistoryItem *context) { | ||||||
|  | @ -744,8 +746,10 @@ void HistoryWidget::highlightMessage(HistoryItem *context) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int HistoryWidget::itemTopForHighlight(HistoryItem *item) const { | int HistoryWidget::itemTopForHighlight(gsl::not_null<HistoryItem*> item) const { | ||||||
| 	auto itemTop = _list->itemTop(item); | 	auto itemTop = _list->itemTop(item); | ||||||
|  | 	t_assert(itemTop >= 0); | ||||||
|  | 
 | ||||||
| 	auto heightLeft = (_scroll->height() - item->height()); | 	auto heightLeft = (_scroll->height() - item->height()); | ||||||
| 	if (heightLeft <= 0) { | 	if (heightLeft <= 0) { | ||||||
| 		return itemTop; | 		return itemTop; | ||||||
|  | @ -1095,10 +1099,10 @@ void HistoryWidget::sendActionDone(const MTPBool &result, mtpRequestId req) { | ||||||
| 
 | 
 | ||||||
| void HistoryWidget::activate() { | void HistoryWidget::activate() { | ||||||
| 	if (_history) { | 	if (_history) { | ||||||
| 		if (!_histInited) { | 		if (!_historyInited) { | ||||||
| 			updateListSize(true); | 			updateHistoryGeometry(true); | ||||||
| 		} else if (hasPendingResizedItems()) { | 		} else if (hasPendingResizedItems()) { | ||||||
| 			updateListSize(); | 			updateHistoryGeometry(); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if (App::wnd()) App::wnd()->setInnerFocus(); | 	if (App::wnd()) App::wnd()->setInnerFocus(); | ||||||
|  | @ -1249,7 +1253,7 @@ void HistoryWidget::notify_migrateUpdated(PeerData *peer) { | ||||||
| 				} else { | 				} else { | ||||||
| 					_migrated = migrated; | 					_migrated = migrated; | ||||||
| 					_list->notifyMigrateUpdated(); | 					_list->notifyMigrateUpdated(); | ||||||
| 					updateListSize(); | 					updateHistoryGeometry(); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} else if (_migrated && _migrated->peer == peer && peer->migrateTo() != _peer) { | 		} else if (_migrated && _migrated->peer == peer && peer->migrateTo() != _peer) { | ||||||
|  | @ -1697,7 +1701,7 @@ void HistoryWidget::fastShowAtEnd(History *h) { | ||||||
| 		clearAllLoadRequests(); | 		clearAllLoadRequests(); | ||||||
| 
 | 
 | ||||||
| 		setMsgId(ShowAtUnreadMsgId); | 		setMsgId(ShowAtUnreadMsgId); | ||||||
| 		_histInited = false; | 		_historyInited = false; | ||||||
| 
 | 
 | ||||||
| 		if (h->isReadyFor(_showAtMsgId)) { | 		if (h->isReadyFor(_showAtMsgId)) { | ||||||
| 			historyLoaded(); | 			historyLoaded(); | ||||||
|  | @ -1788,9 +1792,10 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 				setMsgId(showAtMsgId); | 				setMsgId(showAtMsgId); | ||||||
| 				if (_histInited) { | 				if (_historyInited) { | ||||||
| 					animatedScrollToItem(_showAtMsgId); | 					auto item = getItemFromHistoryOrMigrated(_showAtMsgId); | ||||||
| 					highlightMessage(App::histItemById(_channel, _showAtMsgId)); | 					animatedScrollToY(countInitialScrollTop(), item); | ||||||
|  | 					highlightMessage(item); | ||||||
| 				} else { | 				} else { | ||||||
| 					historyLoaded(); | 					historyLoaded(); | ||||||
| 				} | 				} | ||||||
|  | @ -1829,6 +1834,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re | ||||||
| 
 | 
 | ||||||
| 		destroyUnreadBar(); | 		destroyUnreadBar(); | ||||||
| 		destroyPinnedBar(); | 		destroyPinnedBar(); | ||||||
|  | 		_scrollToAnimation.finish(); | ||||||
| 		_history = _migrated = nullptr; | 		_history = _migrated = nullptr; | ||||||
| 		_peer = nullptr; | 		_peer = nullptr; | ||||||
| 		_channel = NoChannel; | 		_channel = NoChannel; | ||||||
|  | @ -1853,7 +1859,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re | ||||||
| 	clearInlineBot(); | 	clearInlineBot(); | ||||||
| 
 | 
 | ||||||
| 	_showAtMsgId = showAtMsgId; | 	_showAtMsgId = showAtMsgId; | ||||||
| 	_histInited = false; | 	_historyInited = false; | ||||||
| 
 | 
 | ||||||
| 	if (peerId) { | 	if (peerId) { | ||||||
| 		_peer = App::peer(peerId); | 		_peer = App::peer(peerId); | ||||||
|  | @ -2517,7 +2523,7 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages | ||||||
| 
 | 
 | ||||||
| 		setMsgId(_delayedShowAtMsgId); | 		setMsgId(_delayedShowAtMsgId); | ||||||
| 
 | 
 | ||||||
| 		_histInited = false; | 		_historyInited = false; | ||||||
| 		historyLoaded(); | 		historyLoaded(); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -2723,35 +2729,63 @@ void HistoryWidget::visibleAreaUpdated() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void HistoryWidget::preloadHistoryIfNeeded() { | void HistoryWidget::preloadHistoryIfNeeded() { | ||||||
| 	if (_firstLoadRequest || _scroll->isHidden() || !_peer) return; | 	if (_firstLoadRequest || _scroll->isHidden() || !_peer) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	updateHistoryDownVisibility(); | 	updateHistoryDownVisibility(); | ||||||
|  | 	if (!_scrollToAnimation.animating()) { | ||||||
|  | 		preloadHistoryByScroll(); | ||||||
|  | 		checkReplyReturns(); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	int st = _scroll->scrollTop(), stm = _scroll->scrollTopMax(), sh = _scroll->height(); | 	auto scrollTop = _scroll->scrollTop(); | ||||||
| 	if (st + kPreloadHeightsCount * sh >= stm) { | 	if (scrollTop != _lastScrollTop) { | ||||||
|  | 		_lastScrolled = getms(); | ||||||
|  | 		_lastScrollTop = scrollTop; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void HistoryWidget::preloadHistoryByScroll() { | ||||||
|  | 	if (_firstLoadRequest || _scroll->isHidden() || !_peer) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	auto scrollTop = _scroll->scrollTop(); | ||||||
|  | 	auto scrollTopMax = _scroll->scrollTopMax(); | ||||||
|  | 	auto scrollHeight = _scroll->height(); | ||||||
|  | 	if (scrollTop + kPreloadHeightsCount * scrollHeight >= scrollTopMax) { | ||||||
| 		loadMessagesDown(); | 		loadMessagesDown(); | ||||||
| 	} | 	} | ||||||
| 
 | 	if (scrollTop <= kPreloadHeightsCount * scrollHeight) { | ||||||
| 	if (st <= kPreloadHeightsCount * sh) { |  | ||||||
| 		loadMessages(); | 		loadMessages(); | ||||||
| 	} | 	} | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|  | void HistoryWidget::checkReplyReturns() { | ||||||
|  | 	if (_firstLoadRequest || _scroll->isHidden() || !_peer) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	auto scrollTop = _scroll->scrollTop(); | ||||||
|  | 	auto scrollTopMax = _scroll->scrollTopMax(); | ||||||
|  | 	auto scrollHeight = _scroll->height(); | ||||||
| 	while (_replyReturn) { | 	while (_replyReturn) { | ||||||
| 		bool below = (_replyReturn->detached() && _replyReturn->history() == _history && !_history->isEmpty() && _replyReturn->id < _history->blocks.back()->items.back()->id); | 		auto below = (_replyReturn->detached() && _replyReturn->history() == _history && !_history->isEmpty() && _replyReturn->id < _history->blocks.back()->items.back()->id); | ||||||
| 		if (!below) below = (_replyReturn->detached() && _replyReturn->history() == _migrated && !_history->isEmpty()); | 		if (!below) { | ||||||
| 		if (!below) below = (_replyReturn->detached() && _migrated && _replyReturn->history() == _migrated && !_migrated->isEmpty() && _replyReturn->id < _migrated->blocks.back()->items.back()->id); | 			below = (_replyReturn->detached() && _replyReturn->history() == _migrated && !_history->isEmpty()); | ||||||
| 		if (!below && !_replyReturn->detached()) below = (st >= stm) || (_list->itemTop(_replyReturn) < st + sh / 2); | 		} | ||||||
|  | 		if (!below) { | ||||||
|  | 			below = (_replyReturn->detached() && _migrated && _replyReturn->history() == _migrated && !_migrated->isEmpty() && _replyReturn->id < _migrated->blocks.back()->items.back()->id); | ||||||
|  | 		} | ||||||
|  | 		if (!below && !_replyReturn->detached()) { | ||||||
|  | 			below = (scrollTop >= scrollTopMax) || (_list->itemTop(_replyReturn) < scrollTop + scrollHeight / 2); | ||||||
|  | 		} | ||||||
| 		if (below) { | 		if (below) { | ||||||
| 			calcNextReplyReturn(); | 			calcNextReplyReturn(); | ||||||
| 		} else { | 		} else { | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	if (st != _lastScrollTop) { |  | ||||||
| 		_lastScrolled = getms(); |  | ||||||
| 		_lastScrollTop = st; |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void HistoryWidget::onInlineBotCancel() { | void HistoryWidget::onInlineBotCancel() { | ||||||
|  | @ -3113,10 +3147,10 @@ void HistoryWidget::doneShow() { | ||||||
| 	updateReportSpamStatus(); | 	updateReportSpamStatus(); | ||||||
| 	updateBotKeyboard(); | 	updateBotKeyboard(); | ||||||
| 	updateControlsVisibility(); | 	updateControlsVisibility(); | ||||||
| 	if (!_histInited) { | 	if (!_historyInited) { | ||||||
| 		updateListSize(true); | 		updateHistoryGeometry(true); | ||||||
| 	} else if (hasPendingResizedItems()) { | 	} else if (hasPendingResizedItems()) { | ||||||
| 		updateListSize(); | 		updateHistoryGeometry(); | ||||||
| 	} | 	} | ||||||
| 	preloadHistoryIfNeeded(); | 	preloadHistoryIfNeeded(); | ||||||
| 	if (App::wnd()) { | 	if (App::wnd()) { | ||||||
|  | @ -4150,7 +4184,7 @@ void HistoryWidget::inlineBotChanged() { | ||||||
| 
 | 
 | ||||||
| void HistoryWidget::onFieldResize() { | void HistoryWidget::onFieldResize() { | ||||||
| 	moveFieldControls(); | 	moveFieldControls(); | ||||||
| 	updateListSize(); | 	updateHistoryGeometry(); | ||||||
| 	updateField(); | 	updateField(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -4637,7 +4671,7 @@ void HistoryWidget::onReportSpamClear() { | ||||||
| 
 | 
 | ||||||
| void HistoryWidget::peerMessagesUpdated(PeerId peer) { | void HistoryWidget::peerMessagesUpdated(PeerId peer) { | ||||||
| 	if (_peer && _list && peer == _peer->id) { | 	if (_peer && _list && peer == _peer->id) { | ||||||
| 		updateListSize(); | 		updateHistoryGeometry(); | ||||||
| 		updateBotKeyboard(); | 		updateBotKeyboard(); | ||||||
| 		if (!_scroll->isHidden()) { | 		if (!_scroll->isHidden()) { | ||||||
| 			bool unblock = isBlocked(), botStart = isBotStart(), joinChannel = isJoinChannel(), muteUnmute = isMuteUnmute(); | 			bool unblock = isBlocked(), botStart = isBotStart(), joinChannel = isJoinChannel(), muteUnmute = isMuteUnmute(); | ||||||
|  | @ -4712,8 +4746,8 @@ void HistoryWidget::notify_historyItemLayoutChanged(const HistoryItem *item) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void HistoryWidget::notify_handlePendingHistoryUpdate() { | void HistoryWidget::notify_handlePendingHistoryUpdate() { | ||||||
| 	if (hasPendingResizedItems()) { | 	if (hasPendingResizedItems() || _updateHistoryGeometryRequired) { | ||||||
| 		updateListSize(); | 		updateHistoryGeometry(); | ||||||
| 		_list->update(); | 		_list->update(); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -4746,7 +4780,7 @@ void HistoryWidget::updateControlsGeometry() { | ||||||
| 		_reportSpamPanel->setGeometryToLeft(0, _scroll->y(), _chatWidth, _reportSpamPanel->height()); | 		_reportSpamPanel->setGeometryToLeft(0, _scroll->y(), _chatWidth, _reportSpamPanel->height()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	updateListSize(false, false, { ScrollChangeAdd, App::main() ? App::main()->contentScrollAddToY() : 0 }); | 	updateHistoryGeometry(false, false, { ScrollChangeAdd, App::main() ? App::main()->contentScrollAddToY() : 0 }); | ||||||
| 
 | 
 | ||||||
| 	updateFieldSize(); | 	updateFieldSize(); | ||||||
| 
 | 
 | ||||||
|  | @ -4818,8 +4852,64 @@ MsgId HistoryWidget::replyToId() const { | ||||||
| 	return _replyToId ? _replyToId : (_kbReplyTo ? _kbReplyTo->id : 0); | 	return _replyToId ? _replyToId : (_kbReplyTo ? _kbReplyTo->id : 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void HistoryWidget::updateListSize(bool initial, bool loadedDown, const ScrollChange &change) { | int HistoryWidget::countInitialScrollTop() { | ||||||
| 	if (!_history || (initial && _histInited) || (!initial && !_histInited)) return; | 	auto result = ScrollMax; | ||||||
|  | 	if (_history->scrollTopItem || (_migrated && _migrated->scrollTopItem)) { | ||||||
|  | 		result = _list->historyScrollTop(); | ||||||
|  | 	} else if (_showAtMsgId && (_showAtMsgId > 0 && -_showAtMsgId < ServerMaxMsgId)) { | ||||||
|  | 		auto item = getItemFromHistoryOrMigrated(_showAtMsgId); | ||||||
|  | 		auto itemTop = _list->itemTop(item); | ||||||
|  | 		if (itemTop < 0) { | ||||||
|  | 			setMsgId(0); | ||||||
|  | 			return countInitialScrollTop(); | ||||||
|  | 		} else { | ||||||
|  | 			result = itemTopForHighlight(item); | ||||||
|  | 			highlightMessage(item); | ||||||
|  | 		} | ||||||
|  | 	} else if (_history->unreadBar || (_migrated && _migrated->unreadBar)) { | ||||||
|  | 		result = unreadBarTop(); | ||||||
|  | 	} else { | ||||||
|  | 		return countAutomaticScrollTop(); | ||||||
|  | 	} | ||||||
|  | 	return qMin(result, _scroll->scrollTopMax()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int HistoryWidget::countAutomaticScrollTop() { | ||||||
|  | 	auto result = ScrollMax; | ||||||
|  | 	if (_migrated && _migrated->showFrom) { | ||||||
|  | 		result = _list->itemTop(_migrated->showFrom); | ||||||
|  | 		if (result < _scroll->scrollTopMax() + HistoryMessageUnreadBar::height() - HistoryMessageUnreadBar::marginTop()) { | ||||||
|  | 			_migrated->addUnreadBar(); | ||||||
|  | 			if (hasPendingResizedItems()) { | ||||||
|  | 				updateListSize(); | ||||||
|  | 			} | ||||||
|  | 			if (_migrated->unreadBar) { | ||||||
|  | 				setMsgId(ShowAtUnreadMsgId); | ||||||
|  | 				result = countInitialScrollTop(); | ||||||
|  | 				App::wnd()->checkHistoryActivation(); | ||||||
|  | 				return result; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} else if (_history->showFrom) { | ||||||
|  | 		result = _list->itemTop(_history->showFrom); | ||||||
|  | 		if (result < _scroll->scrollTopMax() + HistoryMessageUnreadBar::height() - HistoryMessageUnreadBar::marginTop()) { | ||||||
|  | 			_history->addUnreadBar(); | ||||||
|  | 			if (hasPendingResizedItems()) { | ||||||
|  | 				updateListSize(); | ||||||
|  | 			} | ||||||
|  | 			if (_history->unreadBar) { | ||||||
|  | 				setMsgId(ShowAtUnreadMsgId); | ||||||
|  | 				result = countInitialScrollTop(); | ||||||
|  | 				App::wnd()->checkHistoryActivation(); | ||||||
|  | 				return result; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return qMin(result, _scroll->scrollTopMax()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void HistoryWidget::updateHistoryGeometry(bool initial, bool loadedDown, const ScrollChange &change) { | ||||||
|  | 	if (!_history || (initial && _historyInited) || (!initial && !_historyInited)) return; | ||||||
| 	if (_firstLoadRequest || _a_show.animating()) { | 	if (_firstLoadRequest || _a_show.animating()) { | ||||||
| 		return; // scrollTopMax etc are not working after recountHeight()
 | 		return; // scrollTopMax etc are not working after recountHeight()
 | ||||||
| 	} | 	} | ||||||
|  | @ -4858,16 +4948,8 @@ void HistoryWidget::updateListSize(bool initial, bool loadedDown, const ScrollCh | ||||||
| 		controller()->floatPlayerAreaUpdated().notify(true); | 		controller()->floatPlayerAreaUpdated().notify(true); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	_list->recountHeight(); | 	updateListSize(); | ||||||
| 
 | 	_updateHistoryGeometryRequired = false; | ||||||
| 	bool washidden = _scroll->isHidden(); |  | ||||||
| 	if (washidden) { |  | ||||||
| 		_scroll->show(); |  | ||||||
| 	} |  | ||||||
| 	_list->updateSize(); |  | ||||||
| 	if (washidden) { |  | ||||||
| 		_scroll->hide(); |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	if ((!initial && !wasAtBottom) || (loadedDown && (!_history->showFrom || _history->unreadBar || _history->loadedAtBottom()) && (!_migrated || !_migrated->showFrom || _migrated->unreadBar || _history->loadedAtBottom()))) { | 	if ((!initial && !wasAtBottom) || (loadedDown && (!_history->showFrom || _history->unreadBar || _history->loadedAtBottom()) && (!_migrated || !_migrated->showFrom || _migrated->unreadBar || _history->loadedAtBottom()))) { | ||||||
| 		int toY = _list->historyScrollTop(); | 		int toY = _list->historyScrollTop(); | ||||||
|  | @ -4891,71 +4973,29 @@ void HistoryWidget::updateListSize(bool initial, bool loadedDown, const ScrollCh | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (initial) { | 	if (initial) { | ||||||
| 		_histInited = true; | 		_historyInited = true; | ||||||
| 	} | 	} | ||||||
| 
 | 	auto newScrollTop = initial ? countInitialScrollTop() : countAutomaticScrollTop(); | ||||||
| 	int32 toY = ScrollMax; | 	if (_scroll->scrollTop() == newScrollTop) { | ||||||
| 	if (initial && (_history->scrollTopItem || (_migrated && _migrated->scrollTopItem))) { |  | ||||||
| 		toY = _list->historyScrollTop(); |  | ||||||
| 	} else if (initial && _migrated && _showAtMsgId < 0 && -_showAtMsgId < ServerMaxMsgId) { |  | ||||||
| 		auto item = App::histItemById(0, -_showAtMsgId); |  | ||||||
| 		auto iy = _list->itemTop(item); |  | ||||||
| 		if (iy < 0) { |  | ||||||
| 			setMsgId(0); |  | ||||||
| 			_histInited = false; |  | ||||||
| 			return updateListSize(initial, false, change); |  | ||||||
| 		} else { |  | ||||||
| 			toY = itemTopForHighlight(item); |  | ||||||
| 			highlightMessage(item); |  | ||||||
| 		} |  | ||||||
| 	} else if (initial && _showAtMsgId > 0) { |  | ||||||
| 		auto item = App::histItemById(_channel, _showAtMsgId); |  | ||||||
| 		auto iy = _list->itemTop(item); |  | ||||||
| 		if (iy < 0) { |  | ||||||
| 			setMsgId(0); |  | ||||||
| 			_histInited = false; |  | ||||||
| 			return updateListSize(initial, false, change); |  | ||||||
| 		} else { |  | ||||||
| 			toY = itemTopForHighlight(item); |  | ||||||
| 			highlightMessage(item); |  | ||||||
| 		} |  | ||||||
| 	} else if (initial && (_history->unreadBar || (_migrated && _migrated->unreadBar))) { |  | ||||||
| 		toY = unreadBarTop(); |  | ||||||
| 	} else if (_migrated && _migrated->showFrom) { |  | ||||||
| 		toY = _list->itemTop(_migrated->showFrom); |  | ||||||
| 		if (toY < _scroll->scrollTopMax() + HistoryMessageUnreadBar::height() - HistoryMessageUnreadBar::marginTop()) { |  | ||||||
| 			_migrated->addUnreadBar(); |  | ||||||
| 			if (_migrated->unreadBar) { |  | ||||||
| 				setMsgId(ShowAtUnreadMsgId); |  | ||||||
| 				_histInited = false; |  | ||||||
| 				updateListSize(true); |  | ||||||
| 				App::wnd()->checkHistoryActivation(); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} else if (_history->showFrom) { |  | ||||||
| 		toY = _list->itemTop(_history->showFrom); |  | ||||||
| 		if (toY < _scroll->scrollTopMax() + st::historyUnreadBarHeight) { |  | ||||||
| 			_history->addUnreadBar(); |  | ||||||
| 			if (_history->unreadBar) { |  | ||||||
| 				setMsgId(ShowAtUnreadMsgId); |  | ||||||
| 				_histInited = false; |  | ||||||
| 				updateListSize(true); |  | ||||||
| 				App::wnd()->checkHistoryActivation(); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 	} |  | ||||||
| 	auto scrollMax = _scroll->scrollTopMax(); |  | ||||||
| 	accumulate_min(toY, scrollMax); |  | ||||||
| 	if (_scroll->scrollTop() == toY) { |  | ||||||
| 		visibleAreaUpdated(); | 		visibleAreaUpdated(); | ||||||
| 	} else { | 	} else { | ||||||
| 		synteticScrollToY(toY); | 		synteticScrollToY(newScrollTop); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void HistoryWidget::updateListSize() { | ||||||
|  | 	_list->recountHeight(); | ||||||
|  | 	auto washidden = _scroll->isHidden(); | ||||||
|  | 	if (washidden) { | ||||||
|  | 		_scroll->show(); | ||||||
|  | 	} | ||||||
|  | 	_list->updateSize(); | ||||||
|  | 	if (washidden) { | ||||||
|  | 		_scroll->hide(); | ||||||
|  | 	} | ||||||
|  | 	_updateHistoryGeometryRequired = true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int HistoryWidget::unreadBarTop() const { | int HistoryWidget::unreadBarTop() const { | ||||||
| 	auto getUnreadBar = [this]() -> HistoryItem* { | 	auto getUnreadBar = [this]() -> HistoryItem* { | ||||||
| 		if (_migrated && _migrated->unreadBar) { | 		if (_migrated && _migrated->unreadBar) { | ||||||
|  | @ -4979,9 +5019,9 @@ int HistoryWidget::unreadBarTop() const { | ||||||
| void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector<MTPMessage> &messages) { | void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector<MTPMessage> &messages) { | ||||||
| 	_list->messagesReceived(peer, messages); | 	_list->messagesReceived(peer, messages); | ||||||
| 	if (!_firstLoadRequest) { | 	if (!_firstLoadRequest) { | ||||||
| 		updateListSize(); | 		updateHistoryGeometry(); | ||||||
| 		if (_animActiveTimer.isActive() && _activeAnimMsgId > 0 && _migrated && !_migrated->isEmpty() && _migrated->loadedAtBottom() && _migrated->blocks.back()->items.back()->isGroupMigrate() && _list->historyTop() != _list->historyDrawTop() && _history) { | 		if (_animActiveTimer.isActive() && _activeAnimMsgId > 0 && _migrated && !_migrated->isEmpty() && _migrated->loadedAtBottom() && _migrated->blocks.back()->items.back()->isGroupMigrate() && _list->historyTop() != _list->historyDrawTop() && _history) { | ||||||
| 			HistoryItem *animActiveItem = App::histItemById(_history->channelId(), _activeAnimMsgId); | 			auto animActiveItem = App::histItemById(_history->channelId(), _activeAnimMsgId); | ||||||
| 			if (animActiveItem && animActiveItem->isGroupMigrate()) { | 			if (animActiveItem && animActiveItem->isGroupMigrate()) { | ||||||
| 				_activeAnimMsgId = -_migrated->blocks.back()->items.back()->id; | 				_activeAnimMsgId = -_migrated->blocks.back()->items.back()->id; | ||||||
| 			} | 			} | ||||||
|  | @ -4993,7 +5033,7 @@ void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector<MTPMessage> | ||||||
| void HistoryWidget::addMessagesToBack(PeerData *peer, const QVector<MTPMessage> &messages) { | void HistoryWidget::addMessagesToBack(PeerData *peer, const QVector<MTPMessage> &messages) { | ||||||
| 	_list->messagesReceivedDown(peer, messages); | 	_list->messagesReceivedDown(peer, messages); | ||||||
| 	if (!_firstLoadRequest) { | 	if (!_firstLoadRequest) { | ||||||
| 		updateListSize(false, true, { ScrollChangeNoJumpToBottom, 0 }); | 		updateHistoryGeometry(false, true, { ScrollChangeNoJumpToBottom, 0 }); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -5976,7 +6016,7 @@ void HistoryWidget::peerUpdated(PeerData *data) { | ||||||
| 		if (pinnedMsgVisibilityUpdated()) { | 		if (pinnedMsgVisibilityUpdated()) { | ||||||
| 			resize = true; | 			resize = true; | ||||||
| 		} | 		} | ||||||
| 		updateListSize(); | 		updateHistoryGeometry(); | ||||||
| 		if (_peer->isChannel()) updateReportSpamStatus(); | 		if (_peer->isChannel()) updateReportSpamStatus(); | ||||||
| 		if (App::api()) { | 		if (App::api()) { | ||||||
| 			if (data->isChat() && data->asChat()->noParticipantInfo()) { | 			if (data->isChat() && data->asChat()->noParticipantInfo()) { | ||||||
|  | @ -6102,13 +6142,22 @@ void HistoryWidget::onClearSelected() { | ||||||
| 	if (_list) _list->clearSelectedItems(); | 	if (_list) _list->clearSelectedItems(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | HistoryItem *HistoryWidget::getItemFromHistoryOrMigrated(MsgId genericMsgId) const { | ||||||
|  | 	if (genericMsgId < 0 && -genericMsgId < ServerMaxMsgId && _migrated) { | ||||||
|  | 		return App::histItemById(_migrated->channelId(), -genericMsgId); | ||||||
|  | 	} | ||||||
|  | 	return App::histItemById(_channel, genericMsgId); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void HistoryWidget::onAnimActiveStep() { | void HistoryWidget::onAnimActiveStep() { | ||||||
| 	if (!_history || !_activeAnimMsgId || (_activeAnimMsgId < 0 && (!_migrated || -_activeAnimMsgId >= ServerMaxMsgId))) { | 	if (!_history || !_activeAnimMsgId || (_activeAnimMsgId < 0 && (!_migrated || -_activeAnimMsgId >= ServerMaxMsgId))) { | ||||||
| 		return _animActiveTimer.stop(); | 		return _animActiveTimer.stop(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	HistoryItem *item = (_activeAnimMsgId < 0 && -_activeAnimMsgId < ServerMaxMsgId && _migrated) ? App::histItemById(_migrated->channelId(), -_activeAnimMsgId) : App::histItemById(_channel, _activeAnimMsgId); | 	auto item = getItemFromHistoryOrMigrated(_activeAnimMsgId); | ||||||
| 	if (!item || item->detached()) return _animActiveTimer.stop(); | 	if (!item || item->detached()) { | ||||||
|  | 		return _animActiveTimer.stop(); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (getms() - _animActiveStart > st::activeFadeInDuration + st::activeFadeOutDuration) { | 	if (getms() - _animActiveStart > st::activeFadeInDuration + st::activeFadeOutDuration) { | ||||||
| 		stopAnimActive(); | 		stopAnimActive(); | ||||||
|  | @ -6144,7 +6193,7 @@ void HistoryWidget::updateTopBarSelection() { | ||||||
| 	_nonEmptySelection = (selectedState.count > 0) || selectedState.textSelected; | 	_nonEmptySelection = (selectedState.count > 0) || selectedState.textSelected; | ||||||
| 	_topBar->showSelected(selectedState); | 	_topBar->showSelected(selectedState); | ||||||
| 	updateControlsVisibility(); | 	updateControlsVisibility(); | ||||||
| 	updateListSize(); | 	updateHistoryGeometry(); | ||||||
| 	if (!Ui::isLayerShown() && !App::passcoded()) { | 	if (!Ui::isLayerShown() && !App::passcoded()) { | ||||||
| 		if (_nonEmptySelection || (_list && _list->wasSelectedText()) || _recording || isBotStart() || isBlocked() || !_canSendMessages) { | 		if (_nonEmptySelection || (_list && _list->wasSelectedText()) || _recording || isBotStart() || isBlocked() || !_canSendMessages) { | ||||||
| 			_list->setFocus(); | 			_list->setFocus(); | ||||||
|  |  | ||||||
|  | @ -636,7 +636,8 @@ private: | ||||||
| 		ScrollChangeType type; | 		ScrollChangeType type; | ||||||
| 		int value; | 		int value; | ||||||
| 	}; | 	}; | ||||||
| 	void updateListSize(bool initial = false, bool loadedDown = false, const ScrollChange &change = { ScrollChangeNone, 0 }); | 	void updateHistoryGeometry(bool initial = false, bool loadedDown = false, const ScrollChange &change = { ScrollChangeNone, 0 }); | ||||||
|  | 	void updateListSize(); | ||||||
| 
 | 
 | ||||||
| 	// Does any of the shown histories has this flag set.
 | 	// Does any of the shown histories has this flag set.
 | ||||||
| 	bool hasPendingResizedItems() const { | 	bool hasPendingResizedItems() const { | ||||||
|  | @ -646,7 +647,7 @@ private: | ||||||
| 	// Counts scrollTop for placing the scroll right at the unread
 | 	// Counts scrollTop for placing the scroll right at the unread
 | ||||||
| 	// messages bar, choosing from _history and _migrated unreadBar.
 | 	// messages bar, choosing from _history and _migrated unreadBar.
 | ||||||
| 	int unreadBarTop() const; | 	int unreadBarTop() const; | ||||||
| 	int itemTopForHighlight(HistoryItem *item) const; | 	int itemTopForHighlight(gsl::not_null<HistoryItem*> item) const; | ||||||
| 	void scrollToCurrentVoiceMessage(FullMsgId fromId, FullMsgId toId); | 	void scrollToCurrentVoiceMessage(FullMsgId fromId, FullMsgId toId); | ||||||
| 
 | 
 | ||||||
| 	// Scroll to current y without updating the _lastUserScrolled time.
 | 	// Scroll to current y without updating the _lastUserScrolled time.
 | ||||||
|  | @ -698,13 +699,20 @@ private: | ||||||
| 		setFieldText(TextWithTags(), events, undoHistoryAction); | 		setFieldText(TextWithTags(), events, undoHistoryAction); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	HistoryItem *getItemFromHistoryOrMigrated(MsgId genericMsgId) const; | ||||||
| 	void animatedScrollToItem(MsgId msgId); | 	void animatedScrollToItem(MsgId msgId); | ||||||
|  | 	void animatedScrollToY(int scrollTo, HistoryItem *attachTo = nullptr); | ||||||
| 	void highlightMessage(HistoryItem *context); | 	void highlightMessage(HistoryItem *context); | ||||||
| 	void updateDragAreas(); | 	void updateDragAreas(); | ||||||
| 
 | 
 | ||||||
| 	// when scroll position or scroll area size changed this method
 | 	// when scroll position or scroll area size changed this method
 | ||||||
| 	// updates the boundings of the visible area in HistoryInner
 | 	// updates the boundings of the visible area in HistoryInner
 | ||||||
| 	void visibleAreaUpdated(); | 	void visibleAreaUpdated(); | ||||||
|  | 	int countInitialScrollTop(); | ||||||
|  | 	int countAutomaticScrollTop(); | ||||||
|  | 	void preloadHistoryByScroll(); | ||||||
|  | 	void checkReplyReturns(); | ||||||
|  | 	void scrollToAnimationCallback(FullMsgId attachToId); | ||||||
| 
 | 
 | ||||||
| 	bool readyToForward() const; | 	bool readyToForward() const; | ||||||
| 	bool hasSilentToggle() const; | 	bool hasSilentToggle() const; | ||||||
|  | @ -730,7 +738,8 @@ private: | ||||||
| 	QPointer<HistoryInner> _list; | 	QPointer<HistoryInner> _list; | ||||||
| 	History *_migrated = nullptr; | 	History *_migrated = nullptr; | ||||||
| 	History *_history = nullptr; | 	History *_history = nullptr; | ||||||
| 	bool _histInited = false; // initial updateListSize() called
 | 	bool _historyInited = false; // Initial updateHistoryGeometry() was called.
 | ||||||
|  | 	bool _updateHistoryGeometryRequired = false; // If updateListSize() was called without updateHistoryGeometry().
 | ||||||
| 	int _addToScroll = 0; | 	int _addToScroll = 0; | ||||||
| 
 | 
 | ||||||
| 	int _lastScrollTop = 0; // gifs optimization
 | 	int _lastScrollTop = 0; // gifs optimization
 | ||||||
|  | @ -739,7 +748,7 @@ private: | ||||||
| 
 | 
 | ||||||
| 	TimeMs _lastUserScrolled = 0; | 	TimeMs _lastUserScrolled = 0; | ||||||
| 	bool _synteticScrollEvent = false; | 	bool _synteticScrollEvent = false; | ||||||
| 	Animation _scrollToMediaMessageAnimation; | 	Animation _scrollToAnimation; | ||||||
| 
 | 
 | ||||||
| 	Animation _historyDownShown; | 	Animation _historyDownShown; | ||||||
| 	bool _historyDownIsShown = false; | 	bool _historyDownIsShown = false; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue