fixed gif frame delays, no-repaint-on-scroll optimization done for history
This commit is contained in:
		
							parent
							
								
									5a87bf4114
								
							
						
					
					
						commit
						85bb526294
					
				
					 4 changed files with 124 additions and 63 deletions
				
			
		|  | @ -225,7 +225,7 @@ ClipReader::ClipReader(const FileLocation &location, const QByteArray &data, Cal | ||||||
| , _state(ClipReading) | , _state(ClipReading) | ||||||
| , _width(0) | , _width(0) | ||||||
| , _height(0) | , _height(0) | ||||||
| , _step(FirstFrameNotReadStep) | , _step(WaitingForDimensionsStep) | ||||||
| , _paused(0) | , _paused(0) | ||||||
| , _autoplay(false) | , _autoplay(false) | ||||||
| , _private(0) { | , _private(0) { | ||||||
|  | @ -248,47 +248,69 @@ ClipReader::ClipReader(const FileLocation &location, const QByteArray &data, Cal | ||||||
| 	_clipManagers.at(_threadIndex)->append(this, location, data); | 	_clipManagers.at(_threadIndex)->append(this, location, data); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ClipReader::Frame *ClipReader::frameToShow() const { // 0 means not ready
 | ClipReader::Frame *ClipReader::frameToShow(int32 *index) const { // 0 means not ready
 | ||||||
| 	int32 step = _step.loadAcquire(); | 	int32 step = _step.loadAcquire(), i; | ||||||
| 	if (step == FirstFrameNotReadStep) { | 	if (step == WaitingForDimensionsStep) { | ||||||
| 		return 0; |  | ||||||
| 	} else if (step == WaitingForRequestStep) { |  | ||||||
| 		return _frames; |  | ||||||
| 	} |  | ||||||
| 	return _frames + (((step + 1) / 2) % 3); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| ClipReader::Frame *ClipReader::frameToWrite(int32 *index) const { // 0 means not ready
 |  | ||||||
| 	int32 step = _step.loadAcquire(), i = 0; |  | ||||||
| 	if (step == WaitingForRequestStep) { |  | ||||||
| 		if (index) *index = 0; | 		if (index) *index = 0; | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} else if (step != FirstFrameNotReadStep) { | 	} else if (step == WaitingForRequestStep) { | ||||||
| 		i = (((step + 3) / 2) % 3); | 		i = 0; | ||||||
|  | 	} else if (step == WaitingForFirstFrameStep) { | ||||||
|  | 		i = 0; | ||||||
|  | 	} else { | ||||||
|  | 		i = (step / 2) % 3; | ||||||
| 	} | 	} | ||||||
| 	if (index) *index = i; | 	if (index) *index = i; | ||||||
| 	return _frames + i; | 	return _frames + i; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ClipReader::Frame *ClipReader::frameToWriteNext(bool checkNotWriting) const { | ClipReader::Frame *ClipReader::frameToWrite(int32 *index) const { // 0 means not ready
 | ||||||
| 	int32 step = _step.loadAcquire(); | 	int32 step = _step.loadAcquire(), i; | ||||||
| 	if (step == FirstFrameNotReadStep || step == WaitingForRequestStep || (checkNotWriting && !(step % 2))) { | 	if (step == WaitingForDimensionsStep) { | ||||||
|  | 		i = 0; | ||||||
|  | 	} else if (step == WaitingForRequestStep) { | ||||||
|  | 		if (index) *index = 0; | ||||||
|  | 		return 0; | ||||||
|  | 	} else if (step == WaitingForFirstFrameStep) { | ||||||
|  | 		i = 0; | ||||||
|  | 	} else { | ||||||
|  | 		i = ((step + 2) / 2) % 3; | ||||||
|  | 	} | ||||||
|  | 	if (index) *index = i; | ||||||
|  | 	return _frames + i; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ClipReader::Frame *ClipReader::frameToWriteNext(bool checkNotWriting, int32 *index) const { | ||||||
|  | 	int32 step = _step.loadAcquire(), i; | ||||||
|  | 	if (step == WaitingForDimensionsStep || step == WaitingForRequestStep || (checkNotWriting && (step % 2))) { | ||||||
|  | 		if (index) *index = 0; | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 	return _frames + (((step + 5) / 2) % 3); | 	i = ((step + 4) / 2) % 3; | ||||||
|  | 	if (index) *index = i; | ||||||
|  | 	return _frames + i; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ClipReader::moveToNextShow() const { | void ClipReader::moveToNextShow() const { | ||||||
| 	int32 step = _step.loadAcquire(); | 	int32 step = _step.loadAcquire(); | ||||||
| 	if (step % 2) { | 	if (step == WaitingForDimensionsStep) { | ||||||
| 		_step.storeRelease((step + 1) % 6); | 	} else if (step == WaitingForRequestStep) { | ||||||
|  | 		_step.storeRelease(WaitingForFirstFrameStep); | ||||||
|  | 	} else if (step == WaitingForFirstFrameStep) { | ||||||
|  | 	} else if (!(step % 2)) { | ||||||
|  | 		_step.storeRelease(step + 1); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ClipReader::moveToNextWrite() const { | void ClipReader::moveToNextWrite() const { | ||||||
| 	int32 step = _step.loadAcquire(); | 	int32 step = _step.loadAcquire(); | ||||||
| 	if (!(step % 2)) { | 	if (step == WaitingForDimensionsStep) { | ||||||
| 		_step.storeRelease(step + 1); | 		_step.storeRelease(WaitingForRequestStep); | ||||||
|  | 	} else if (step == WaitingForRequestStep) { | ||||||
|  | 	} else if (step == WaitingForFirstFrameStep) { | ||||||
|  | 		_step.storeRelease(0); | ||||||
|  | 	} else if (step % 2) { | ||||||
|  | 		_step.storeRelease((step + 1) % 6); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -313,7 +335,7 @@ void ClipReader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, b | ||||||
| 		request.outerh = outerh * factor; | 		request.outerh = outerh * factor; | ||||||
| 		request.rounded = rounded; | 		request.rounded = rounded; | ||||||
| 		_frames[0].request = _frames[1].request = _frames[2].request = request; | 		_frames[0].request = _frames[1].request = _frames[2].request = request; | ||||||
| 		_step.storeRelease(0); // start working
 | 		moveToNextShow(); | ||||||
| 		_clipManagers.at(_threadIndex)->start(this); | 		_clipManagers.at(_threadIndex)->start(this); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -322,9 +344,8 @@ QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 oute | ||||||
| 	Frame *frame = frameToShow(); | 	Frame *frame = frameToShow(); | ||||||
| 	t_assert(frame != 0); | 	t_assert(frame != 0); | ||||||
| 
 | 
 | ||||||
| 	frame->displayed = true; |  | ||||||
| 	if (ms) { | 	if (ms) { | ||||||
| 		frame->when = ms; | 		frame->displayed.storeRelease(1); | ||||||
| 		if (_paused.loadAcquire()) { | 		if (_paused.loadAcquire()) { | ||||||
| 			_paused.storeRelease(0); | 			_paused.storeRelease(0); | ||||||
| 			if (_clipManagers.size() <= _threadIndex) error(); | 			if (_clipManagers.size() <= _threadIndex) error(); | ||||||
|  | @ -332,6 +353,8 @@ QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 oute | ||||||
| 				_clipManagers.at(_threadIndex)->update(this); | 				_clipManagers.at(_threadIndex)->update(this); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	} else { | ||||||
|  | 		frame->displayed.storeRelease(-1); // displayed, but should be paused
 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	int32 factor(cIntRetinaFactor()); | 	int32 factor(cIntRetinaFactor()); | ||||||
|  | @ -835,9 +858,7 @@ public: | ||||||
| 	, _frame(0) | 	, _frame(0) | ||||||
| 	, _width(0) | 	, _width(0) | ||||||
| 	, _height(0) | 	, _height(0) | ||||||
| 	, _previousMs(0) | 	, _nextFrameWhen(0) | ||||||
| 	, _currentMs(0) |  | ||||||
| 	, _nextUpdateMs(0) |  | ||||||
| 	, _paused(false) { | 	, _paused(false) { | ||||||
| 		if (_data.isEmpty() && !_location->accessEnable()) { | 		if (_data.isEmpty() && !_location->accessEnable()) { | ||||||
| 			error(); | 			error(); | ||||||
|  | @ -868,23 +889,19 @@ public: | ||||||
| 			return start(ms); | 			return start(ms); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (!_paused && ms >= _nextUpdateMs) { | 		if (!_paused && ms >= _nextFrameWhen) { | ||||||
| 			return ClipProcessRepaint; | 			return ClipProcessRepaint; | ||||||
| 		} | 		} | ||||||
| 		return ClipProcessWait; | 		return ClipProcessWait; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ClipProcessResult finishProcess(uint64 ms) { | 	ClipProcessResult finishProcess(uint64 ms) { | ||||||
| 		_previousMs = _currentMs; |  | ||||||
| 		if (!prepareNextFrame()) { | 		if (!prepareNextFrame()) { | ||||||
| 			return error(); | 			return error(); | ||||||
| 		} | 		} | ||||||
| 		if (ms >= _nextUpdateMs) { | 		if (ms >= _nextFrameWhen && !prepareNextFrame(true)) { | ||||||
| 			if (!prepareNextFrame()) { | 			return error(); | ||||||
| 				return error(); |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 		_currentMs = qMax(ms, _nextUpdateMs); |  | ||||||
| 		return ClipProcessCopyFrame; | 		return ClipProcessCopyFrame; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -893,15 +910,17 @@ public: | ||||||
| 		return qMax(delay, 5); | 		return qMax(delay, 5); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool prepareNextFrame() { | 	bool prepareNextFrame(bool keepup = false) { | ||||||
| 		t_assert(frame() != 0 && _request.valid()); | 		t_assert(frame() != 0 && _request.valid()); | ||||||
| 		if (!_implementation->readNextFrame(frame()->original, frame()->alpha, QSize(_request.framew, _request.frameh))) { | 		if (!_implementation->readNextFrame(frame()->original, frame()->alpha, QSize(_request.framew, _request.frameh))) { | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
| 		_nextUpdateMs = _currentMs + nextFrameDelay(); | 		_nextFrameWhen += nextFrameDelay(); | ||||||
|  | 		if (keepup) _nextFrameWhen = qMax(_nextFrameWhen, getms()); | ||||||
| 		frame()->original.setDevicePixelRatio(_request.factor); | 		frame()->original.setDevicePixelRatio(_request.factor); | ||||||
| 		frame()->pix = QPixmap(); | 		frame()->pix = QPixmap(); | ||||||
| 		frame()->pix = _prepareFrame(_request, frame()->original, frame()->alpha, frame()->cache); | 		frame()->pix = _prepareFrame(_request, frame()->original, frame()->alpha, frame()->cache); | ||||||
|  | 		frame()->when = _nextFrameWhen; | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -962,11 +981,12 @@ private: | ||||||
| 
 | 
 | ||||||
| 	ClipFrameRequest _request; | 	ClipFrameRequest _request; | ||||||
| 	struct Frame { | 	struct Frame { | ||||||
| 		Frame() : alpha(true) { | 		Frame() : alpha(true), when(0) { | ||||||
| 		} | 		} | ||||||
| 		QPixmap pix; | 		QPixmap pix; | ||||||
| 		QImage original, cache; | 		QImage original, cache; | ||||||
| 		bool alpha; | 		bool alpha; | ||||||
|  | 		uint64 when; | ||||||
| 	}; | 	}; | ||||||
| 	Frame _frames[3]; | 	Frame _frames[3]; | ||||||
| 	int32 _frame; | 	int32 _frame; | ||||||
|  | @ -976,7 +996,7 @@ private: | ||||||
| 
 | 
 | ||||||
| 	int32 _width, _height; | 	int32 _width, _height; | ||||||
| 
 | 
 | ||||||
| 	uint64 _previousMs, _currentMs, _nextUpdateMs; | 	uint64 _nextFrameWhen; | ||||||
| 
 | 
 | ||||||
| 	bool _paused; | 	bool _paused; | ||||||
| 
 | 
 | ||||||
|  | @ -1070,13 +1090,16 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess | ||||||
| 	if (result == ClipProcessStarted) { | 	if (result == ClipProcessStarted) { | ||||||
| 		_loadLevel.fetchAndAddRelaxed(reader->_width * reader->_height - AverageGifSize); | 		_loadLevel.fetchAndAddRelaxed(reader->_width * reader->_height - AverageGifSize); | ||||||
| 	} | 	} | ||||||
| 	if (!reader->_paused && (result == ClipProcessRepaint || result == ClipProcessWait)) { | 	if (!reader->_paused && result == ClipProcessRepaint) { | ||||||
| 		ClipReader::Frame *other = it.key()->frameToWriteNext(false); | 		int32 ishowing, iprevious; | ||||||
| 		t_assert(other != 0); | 		ClipReader::Frame *showing = it.key()->frameToShow(&ishowing), *previous = it.key()->frameToWriteNext(false, &iprevious); | ||||||
| 		if (other->when && other->when + WaitBeforeGifPause < qMax(reader->_previousMs, ms)) { | 		t_assert(previous != 0 && showing != 0 && ishowing >= 0 && iprevious >= 0); | ||||||
| 			reader->_paused = true; | 		if (reader->_frames[ishowing].when > 0 && showing->displayed.loadAcquire() <= 0) { // current frame was not shown
 | ||||||
| 			it.key()->_paused.storeRelease(1); | 			if (reader->_frames[ishowing].when + WaitBeforeGifPause < ms || (reader->_frames[iprevious].when && previous->displayed.loadAcquire() <= 0)) { | ||||||
| 			result = ClipProcessPaused; | 				reader->_paused = true; | ||||||
|  | 				it.key()->_paused.storeRelease(1); | ||||||
|  | 				result = ClipProcessPaused; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if (result == ClipProcessStarted || result == ClipProcessCopyFrame) { | 	if (result == ClipProcessStarted || result == ClipProcessCopyFrame) { | ||||||
|  | @ -1085,14 +1108,17 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess | ||||||
| 		frame->clear(); | 		frame->clear(); | ||||||
| 		frame->pix = reader->frame()->pix; | 		frame->pix = reader->frame()->pix; | ||||||
| 		frame->original = reader->frame()->original; | 		frame->original = reader->frame()->original; | ||||||
| 		frame->displayed = false; | 		frame->displayed.storeRelease(0); | ||||||
| 		it.key()->moveToNextWrite(); |  | ||||||
| 		if (result == ClipProcessStarted) { | 		if (result == ClipProcessStarted) { | ||||||
|  | 			reader->_nextFrameWhen = ms; | ||||||
|  | 			it.key()->moveToNextWrite(); | ||||||
| 			emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit); | 			emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit); | ||||||
| 		} | 		} | ||||||
| 	} else if (result == ClipProcessPaused) { | 	} else if (result == ClipProcessPaused) { | ||||||
|  | 		it.key()->moveToNextWrite(); | ||||||
| 		emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit); | 		emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit); | ||||||
| 	} else if (result == ClipProcessRepaint) { | 	} else if (result == ClipProcessRepaint) { | ||||||
|  | 		it.key()->moveToNextWrite(); | ||||||
| 		emit callback(it.key(), it.key()->threadIndex(), ClipReaderRepaint); | 		emit callback(it.key(), it.key()->threadIndex(), ClipReaderRepaint); | ||||||
| 	} | 	} | ||||||
| 	return true; | 	return true; | ||||||
|  | @ -1174,7 +1200,7 @@ void ClipReadManager::process() { | ||||||
| 				return; | 				return; | ||||||
| 			} | 			} | ||||||
| 			ms = getms(); | 			ms = getms(); | ||||||
| 			i.value() = reader->_nextUpdateMs ? reader->_nextUpdateMs : (ms + 86400 * 1000ULL); | 			i.value() = reader->_nextFrameWhen ? reader->_nextFrameWhen : (ms + 86400 * 1000ULL); | ||||||
| 		} | 		} | ||||||
| 		if (!reader->_paused && i.value() < minms) { | 		if (!reader->_paused && i.value() < minms) { | ||||||
| 			minms = i.value(); | 			minms = i.value(); | ||||||
|  |  | ||||||
|  | @ -497,8 +497,9 @@ enum ClipReaderNotification { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| enum ClipReaderSteps { | enum ClipReaderSteps { | ||||||
| 	FirstFrameNotReadStep = -2, | 	WaitingForDimensionsStep = -3, // before ClipReaderPrivate read the first image and got the original frame size
 | ||||||
| 	WaitingForRequestStep = -1, | 	WaitingForRequestStep = -2, // before ClipReader got the original frame size and prepared the frame request
 | ||||||
|  | 	WaitingForFirstFrameStep = -1, // before ClipReaderPrivate got the frame request and started waiting for the 1-2 delay
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class ClipReaderPrivate; | class ClipReaderPrivate; | ||||||
|  | @ -528,7 +529,7 @@ public: | ||||||
| 	} | 	} | ||||||
| 	bool currentDisplayed() const { | 	bool currentDisplayed() const { | ||||||
| 		Frame *frame = frameToShow(); | 		Frame *frame = frameToShow(); | ||||||
| 		return frame ? frame->displayed : true; | 		return frame ? (frame->displayed.loadAcquire() != 0) : true; | ||||||
| 	} | 	} | ||||||
| 	bool paused() const { | 	bool paused() const { | ||||||
| 		return _paused.loadAcquire(); | 		return _paused.loadAcquire(); | ||||||
|  | @ -542,7 +543,8 @@ public: | ||||||
| 
 | 
 | ||||||
| 	ClipState state() const; | 	ClipState state() const; | ||||||
| 	bool started() const { | 	bool started() const { | ||||||
| 		return _step.loadAcquire() >= 0; | 		int32 step = _step.loadAcquire(); | ||||||
|  | 		return (step == WaitingForFirstFrameStep) || (step >= 0); | ||||||
| 	} | 	} | ||||||
| 	bool ready() const; | 	bool ready() const; | ||||||
| 
 | 
 | ||||||
|  | @ -561,7 +563,7 @@ private: | ||||||
| 
 | 
 | ||||||
| 	mutable QAtomicInt _step; // -2, -1 - init, 0-5 - work, show ((state + 1) / 2) % 3 state, write ((state + 3) / 2) % 3
 | 	mutable QAtomicInt _step; // -2, -1 - init, 0-5 - work, show ((state + 1) / 2) % 3 state, write ((state + 3) / 2) % 3
 | ||||||
| 	struct Frame { | 	struct Frame { | ||||||
| 		Frame() : displayed(false), when(0) { | 		Frame() : displayed(false) { | ||||||
| 		} | 		} | ||||||
| 		void clear() { | 		void clear() { | ||||||
| 			pix = QPixmap(); | 			pix = QPixmap(); | ||||||
|  | @ -570,13 +572,12 @@ private: | ||||||
| 		QPixmap pix; | 		QPixmap pix; | ||||||
| 		QImage original; | 		QImage original; | ||||||
| 		ClipFrameRequest request; | 		ClipFrameRequest request; | ||||||
| 		bool displayed; | 		QAtomicInt displayed; | ||||||
| 		uint64 when; |  | ||||||
| 	}; | 	}; | ||||||
| 	mutable Frame _frames[3]; | 	mutable Frame _frames[3]; | ||||||
| 	Frame *frameToShow() const; // 0 means not ready
 | 	Frame *frameToShow(int32 *index = 0) const; // 0 means not ready
 | ||||||
| 	Frame *frameToWrite(int32 *index = 0) const; // 0 means not ready
 | 	Frame *frameToWrite(int32 *index = 0) const; // 0 means not ready
 | ||||||
| 	Frame *frameToWriteNext(bool check) const; | 	Frame *frameToWriteNext(bool check, int32 *index = 0) const; | ||||||
| 	void moveToNextShow() const; | 	void moveToNextShow() const; | ||||||
| 	void moveToNextWrite() const; | 	void moveToNextWrite() const; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2630,6 +2630,8 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) | ||||||
| , _migrated(0) | , _migrated(0) | ||||||
| , _history(0) | , _history(0) | ||||||
| , _histInited(false) | , _histInited(false) | ||||||
|  | , _lastScroll(0) | ||||||
|  | , _lastScrolled(0) | ||||||
| , _toHistoryEnd(this, st::historyToEnd) | , _toHistoryEnd(this, st::historyToEnd) | ||||||
| , _collapseComments(this) | , _collapseComments(this) | ||||||
| , _attachMention(this) | , _attachMention(this) | ||||||
|  | @ -2722,6 +2724,9 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) | ||||||
| 		connect(audioCapture(), SIGNAL(onDone(QByteArray,qint32)), this, SLOT(onRecordDone(QByteArray,qint32))); | 		connect(audioCapture(), SIGNAL(onDone(QByteArray,qint32)), this, SLOT(onRecordDone(QByteArray,qint32))); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	_updateHistoryItems.setSingleShot(true); | ||||||
|  | 	connect(&_updateHistoryItems, SIGNAL(timeout()), this, SLOT(onUpdateHistoryItems())); | ||||||
|  | 
 | ||||||
| 	_scrollTimer.setSingleShot(false); | 	_scrollTimer.setSingleShot(false); | ||||||
| 
 | 
 | ||||||
| 	_sendActionStopTimer.setSingleShot(true); | 	_sendActionStopTimer.setSingleShot(true); | ||||||
|  | @ -3508,6 +3513,8 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re | ||||||
| 		_scroll.setWidget(_list); | 		_scroll.setWidget(_list); | ||||||
| 		_list->show(); | 		_list->show(); | ||||||
| 
 | 
 | ||||||
|  | 		_updateHistoryItems.stop(); | ||||||
|  | 
 | ||||||
| 		if (_history->lastWidth || _history->isReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop)) { | 		if (_history->lastWidth || _history->isReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop)) { | ||||||
| 			_fixedInScrollMsgId = 0; | 			_fixedInScrollMsgId = 0; | ||||||
| 			_fixedInScrollMsgTop = 0; | 			_fixedInScrollMsgTop = 0; | ||||||
|  | @ -4360,6 +4367,11 @@ void HistoryWidget::onListScroll() { | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	if (st != _lastScroll) { | ||||||
|  | 		_lastScrolled = getms(); | ||||||
|  | 		_lastScroll = st; | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void HistoryWidget::onVisibleChanged() { | void HistoryWidget::onVisibleChanged() { | ||||||
|  | @ -4407,8 +4419,9 @@ void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) { | ||||||
| 	_saveDraftStart = getms(); | 	_saveDraftStart = getms(); | ||||||
| 	onDraftSave(); | 	onDraftSave(); | ||||||
| 
 | 
 | ||||||
| 	onCheckMentionDropdown(); | 	if (!_attachMention.isHidden()) _attachMention.hideStart(); | ||||||
| 	if (!_attachType.isHidden()) _attachType.hideStart(); | 	if (!_attachType.isHidden()) _attachType.hideStart(); | ||||||
|  | 	if (!_emojiPan.isHidden()) _emojiPan.hideStart(); | ||||||
| 
 | 
 | ||||||
| 	if (replyTo < 0) cancelReply(lastKeyboardUsed); | 	if (replyTo < 0) cancelReply(lastKeyboardUsed); | ||||||
| 	if (_previewData && _previewData->pendingTill) previewCancel(); | 	if (_previewData && _previewData->pendingTill) previewCancel(); | ||||||
|  | @ -5834,7 +5847,21 @@ bool HistoryWidget::isItemVisible(HistoryItem *item) { | ||||||
| 
 | 
 | ||||||
| void HistoryWidget::ui_repaintHistoryItem(const HistoryItem *item) { | void HistoryWidget::ui_repaintHistoryItem(const HistoryItem *item) { | ||||||
| 	if (_peer && _list && (item->history() == _history || (_migrated && item->history() == _migrated))) { | 	if (_peer && _list && (item->history() == _history || (_migrated && item->history() == _migrated))) { | ||||||
| 		_list->repaintItem(item); | 		uint64 ms = getms(); | ||||||
|  | 		if (_lastScrolled + 100 <= ms) { | ||||||
|  | 			_list->repaintItem(item); | ||||||
|  | 		} else { | ||||||
|  | 			_updateHistoryItems.start(_lastScrolled + 100 - ms); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void HistoryWidget::onUpdateHistoryItems() { | ||||||
|  | 	uint64 ms = getms(); | ||||||
|  | 	if (_lastScrolled + 100 <= ms) { | ||||||
|  | 		_list->update(); | ||||||
|  | 	} else { | ||||||
|  | 		_updateHistoryItems.start(_lastScrolled + 100 - ms); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -6459,8 +6486,9 @@ void HistoryWidget::onInlineResultSend(InlineResult *result, UserData *bot) { | ||||||
| 		Local::writeRecentHashtagsAndBots(); | 		Local::writeRecentHashtagsAndBots(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	onCheckMentionDropdown(); | 	if (!_attachMention.isHidden()) _attachMention.hideStart(); | ||||||
| 	if (!_attachType.isHidden()) _attachType.hideStart(); | 	if (!_attachType.isHidden()) _attachType.hideStart(); | ||||||
|  | 	if (!_emojiPan.isHidden()) _emojiPan.hideStart(); | ||||||
| 
 | 
 | ||||||
| 	_field.setFocus(); | 	_field.setFocus(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -682,6 +682,8 @@ public slots: | ||||||
| 	void onRecordDone(QByteArray result, qint32 samples); | 	void onRecordDone(QByteArray result, qint32 samples); | ||||||
| 	void onRecordUpdate(qint16 level, qint32 samples); | 	void onRecordUpdate(qint16 level, qint32 samples); | ||||||
| 
 | 
 | ||||||
|  | 	void onUpdateHistoryItems(); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
| 
 | 
 | ||||||
| 	MsgId _replyToId; | 	MsgId _replyToId; | ||||||
|  | @ -771,6 +773,10 @@ private: | ||||||
| 	History *_migrated, *_history; | 	History *_migrated, *_history; | ||||||
| 	bool _histInited; // initial updateListSize() called
 | 	bool _histInited; // initial updateListSize() called
 | ||||||
| 
 | 
 | ||||||
|  | 	int32 _lastScroll; | ||||||
|  | 	uint64 _lastScrolled; | ||||||
|  | 	QTimer _updateHistoryItems; // gifs optimization
 | ||||||
|  | 
 | ||||||
| 	IconedButton _toHistoryEnd; | 	IconedButton _toHistoryEnd; | ||||||
| 	CollapseButton _collapseComments; | 	CollapseButton _collapseComments; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 John Preston
						John Preston