Highlight all mentions when marking them read.

This commit is contained in:
John Preston 2017-08-25 18:17:46 +03:00
parent 20efa47126
commit 5a20014b1a
11 changed files with 150 additions and 86 deletions

View file

@ -432,6 +432,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
} }
if (item->mentionsMe() && item->isMediaUnread()) { if (item->mentionsMe() && item->isMediaUnread()) {
readMentions.insert(item); readMentions.insert(item);
_widget->enqueueMessageHighlight(item);
} }
int32 h = item->height(); int32 h = item->height();
@ -482,6 +483,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
} }
if (item->mentionsMe() && item->isMediaUnread()) { if (item->mentionsMe() && item->isMediaUnread()) {
readMentions.insert(item); readMentions.insert(item);
_widget->enqueueMessageHighlight(item);
} }
} }
p.translate(0, h); p.translate(0, h);

View file

@ -600,9 +600,14 @@ TextSelection shiftSelection(TextSelection selection, uint16 byLength) {
} // namespace internal } // namespace internal
HistoryItem::HistoryItem(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime msgDate, int32 from) : HistoryElement() HistoryItem::HistoryItem(
, id(msgId) not_null<History*> history,
, date(msgDate) MsgId id,
MTPDmessage::Flags flags,
QDateTime date,
UserId from) : HistoryElement()
, id(id)
, date(date)
, _history(history) , _history(history)
, _from(from ? App::user(from) : history->peer) , _from(from ? App::user(from) : history->peer)
, _flags(flags | MTPDmessage_ClientFlag::f_pending_init_dimensions | MTPDmessage_ClientFlag::f_pending_resize) , _flags(flags | MTPDmessage_ClientFlag::f_pending_init_dimensions | MTPDmessage_ClientFlag::f_pending_resize)

View file

@ -526,7 +526,7 @@ public:
} }
void addLogEntryOriginal(WebPageId localId, const QString &label, const TextWithEntities &content); void addLogEntryOriginal(WebPageId localId, const QString &label, const TextWithEntities &content);
History *history() const { not_null<History*> history() const {
return _history; return _history;
} }
PeerData *from() const { PeerData *from() const {
@ -921,7 +921,12 @@ public:
~HistoryItem(); ~HistoryItem();
protected: protected:
HistoryItem(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime msgDate, int32 from); HistoryItem(
not_null<History*> history,
MsgId id,
MTPDmessage::Flags flags,
QDateTime date,
UserId from);
// To completely create history item we need to call // To completely create history item we need to call
// a virtual method, it can not be done from constructor. // a virtual method, it can not be done from constructor.
@ -938,7 +943,7 @@ protected:
void finishEdition(int oldKeyboardTop); void finishEdition(int oldKeyboardTop);
void finishEditionToEmpty(); void finishEditionToEmpty();
not_null<History*> _history; const not_null<History*> _history;
not_null<PeerData*> _from; not_null<PeerData*> _from;
HistoryBlock *_block = nullptr; HistoryBlock *_block = nullptr;
int _indexInBlock = -1; int _indexInBlock = -1;

View file

@ -1613,12 +1613,10 @@ void HistoryMessage::draw(Painter &p, QRect clip, TextSelection selection, TimeM
} }
} }
auto fullAnimMs = App::main() ? App::main()->animActiveTimeStart(this) : 0LL; auto fullAnimMs = App::main() ? App::main()->highlightStartTime(this) : 0LL;
if (fullAnimMs > 0 && fullAnimMs <= ms) { if (fullAnimMs > 0 && fullAnimMs <= ms) {
int animms = ms - fullAnimMs; auto animms = ms - fullAnimMs;
if (animms > st::activeFadeInDuration + st::activeFadeOutDuration) { if (animms < st::activeFadeInDuration + st::activeFadeOutDuration) {
App::main()->stopAnimActive();
} else {
auto top = marginTop(); auto top = marginTop();
auto bottom = marginBottom(); auto bottom = marginBottom();
auto fill = qMin(top, bottom); auto fill = qMin(top, bottom);

View file

@ -188,16 +188,18 @@ int WideChatWidth() {
return st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left(); return st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left();
} }
void ServiceMessagePainter::paint(Painter &p, const HistoryService *message, const PaintContext &context, int height) { void ServiceMessagePainter::paint(
Painter &p,
not_null<const HistoryService*> message,
const PaintContext &context,
int height) {
auto g = message->countGeometry(); auto g = message->countGeometry();
if (g.width() < 1) return; if (g.width() < 1) return;
auto fullAnimMs = App::main() ? App::main()->animActiveTimeStart(message) : 0LL; auto fullAnimMs = App::main() ? App::main()->highlightStartTime(message) : 0LL;
if (fullAnimMs > 0 && fullAnimMs <= context.ms) { if (fullAnimMs > 0 && fullAnimMs <= context.ms) {
int animms = context.ms - fullAnimMs; auto animms = context.ms - fullAnimMs;
if (animms > st::activeFadeInDuration + st::activeFadeOutDuration) { if (animms < st::activeFadeInDuration + st::activeFadeOutDuration) {
App::main()->stopAnimActive();
} else {
auto top = st::msgServiceMargin.top(); auto top = st::msgServiceMargin.top();
auto bottom = st::msgServiceMargin.bottom(); auto bottom = st::msgServiceMargin.bottom();
auto fill = qMin(top, bottom); auto fill = qMin(top, bottom);

View file

@ -39,7 +39,11 @@ struct PaintContext {
class ServiceMessagePainter { class ServiceMessagePainter {
public: public:
static void paint(Painter &p, const HistoryService *message, const PaintContext &context, int height); static void paint(
Painter &p,
not_null<const HistoryService*> message,
const PaintContext &context,
int height);
static void paintDate(Painter &p, const QDateTime &date, int y, int w); static void paintDate(Painter &p, const QDateTime &date, int y, int w);
static void paintDate(Painter &p, const QString &dateText, int dateTextWidth, int y, int w); static void paintDate(Painter &p, const QString &dateText, int dateTextWidth, int y, int w);

View file

@ -680,8 +680,7 @@ HistoryWidget::HistoryWidget(QWidget *parent, not_null<Window::Controller*> cont
_sendActionStopTimer.setSingleShot(true); _sendActionStopTimer.setSingleShot(true);
_animActiveTimer.setSingleShot(false); _highlightTimer.setCallback([this] { updateHighlightedMessage(); });
connect(&_animActiveTimer, SIGNAL(timeout()), this, SLOT(onAnimActiveStep()));
_membersDropdownShowTimer.setSingleShot(true); _membersDropdownShowTimer.setSingleShot(true);
connect(&_membersDropdownShowTimer, SIGNAL(timeout()), this, SLOT(onMembersDropdownShow())); connect(&_membersDropdownShowTimer, SIGNAL(timeout()), this, SLOT(onMembersDropdownShow()));
@ -948,24 +947,108 @@ void HistoryWidget::scrollToAnimationCallback(FullMsgId attachToId) {
} }
} }
void HistoryWidget::highlightMessage(HistoryItem *context) { void HistoryWidget::enqueueMessageHighlight(not_null<HistoryItem*> item) {
Expects(_list != nullptr); auto enqueueMessageId = [this](MsgId universalId) {
if (_highlightQueue.empty() && !_highlightTimer.isActive()) {
highlightMessage(universalId);
} else if (_highlightedMessageId != universalId
&& !base::contains(_highlightQueue, universalId)) {
_highlightQueue.push_back(universalId);
checkNextHighlight();
}
};
if (item->history() == _history) {
enqueueMessageId(item->id);
} else if (item->history() == _migrated) {
enqueueMessageId(-item->id);
}
}
_animActiveStart = getms(); void HistoryWidget::highlightMessage(MsgId universalMessageId) {
_animActiveTimer.start(AnimationTimerDelta); _highlightStart = getms();
_activeAnimMsgId = _showAtMsgId; _highlightedMessageId = universalMessageId;
if (context _highlightTimer.callEach(AnimationTimerDelta);
&& context->history() == _history
&& context->isGroupMigrate() adjustHighlightedMessageToMigrated();
}
void HistoryWidget::adjustHighlightedMessageToMigrated() {
if (_history
&& _highlightTimer.isActive()
&& _highlightedMessageId > 0
&& _migrated && _migrated
&& !_migrated->isEmpty() && !_migrated->isEmpty()
&& _migrated->loadedAtBottom() && _migrated->loadedAtBottom()
&& _migrated->blocks.back()->items.back()->isGroupMigrate() && _migrated->blocks.back()->items.back()->isGroupMigrate()
&& _list->historyTop() != _list->historyDrawTop()) { && _list->historyTop() != _list->historyDrawTop()) {
_activeAnimMsgId = -_migrated->blocks.back()->items.back()->id; auto highlighted = App::histItemById(
_history->channelId(),
_highlightedMessageId);
if (highlighted && highlighted->isGroupMigrate()) {
_highlightedMessageId = -_migrated->blocks.back()->items.back()->id;
}
} }
} }
void HistoryWidget::checkNextHighlight() {
if (_highlightTimer.isActive()) {
return;
}
auto nextHighlight = [this] {
while (!_highlightQueue.empty()) {
auto msgId = _highlightQueue.front();
_highlightQueue.pop_front();
auto item = getItemFromHistoryOrMigrated(msgId);
if (item && !item->detached()) {
return msgId;
}
}
return 0;
}();
if (!nextHighlight) {
return;
}
highlightMessage(nextHighlight);
}
void HistoryWidget::updateHighlightedMessage() {
auto item = getItemFromHistoryOrMigrated(_highlightedMessageId);
if (!item || item->detached()) {
return stopMessageHighlight();
}
auto duration = st::activeFadeInDuration + st::activeFadeOutDuration;
if (getms() - _highlightStart > duration) {
return stopMessageHighlight();
}
Ui::repaintHistoryItem(item);
}
TimeMs HistoryWidget::highlightStartTime(not_null<const HistoryItem*> item) const {
auto isHighlighted = [this](not_null<const HistoryItem*> item) {
if (item->id == _highlightedMessageId) {
return (item->history() == _history);
} else if (item->id == -_highlightedMessageId) {
return (item->history() == _migrated);
}
return false;
};
return (isHighlighted(item) && _highlightTimer.isActive())
? _highlightStart
: 0;
}
void HistoryWidget::stopMessageHighlight() {
_highlightTimer.cancel();
_highlightedMessageId = 0;
checkNextHighlight();
}
void HistoryWidget::clearHighlightMessages() {
_highlightQueue.clear();
stopMessageHighlight();
}
int HistoryWidget::itemTopForHighlight(not_null<HistoryItem*> item) const { int HistoryWidget::itemTopForHighlight(not_null<HistoryItem*> item) const {
auto itemTop = _list->itemTop(item); auto itemTop = _list->itemTop(item);
Assert(itemTop >= 0); Assert(itemTop >= 0);
@ -1644,6 +1727,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
showAtMsgId = ShowAtTheEndMsgId; showAtMsgId = ShowAtTheEndMsgId;
} }
clearHighlightMessages();
if (_history) { if (_history) {
if (_peer->id == peerId && !reload) { if (_peer->id == peerId && !reload) {
updateForwarding(); updateForwarding();
@ -1676,7 +1760,6 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
auto item = getItemFromHistoryOrMigrated(_showAtMsgId); auto item = getItemFromHistoryOrMigrated(_showAtMsgId);
animatedScrollToY(countInitialScrollTop(), item); animatedScrollToY(countInitialScrollTop(), item);
highlightMessage(item);
} else { } else {
historyLoaded(); historyLoaded();
} }
@ -4808,7 +4891,7 @@ int HistoryWidget::countInitialScrollTop() {
return countInitialScrollTop(); return countInitialScrollTop();
} else { } else {
result = itemTopForHighlight(item); result = itemTopForHighlight(item);
highlightMessage(item); enqueueMessageHighlight(item);
} }
} else if (_history->unreadBar || (_migrated && _migrated->unreadBar)) { } else if (_history->unreadBar || (_migrated && _migrated->unreadBar)) {
result = unreadBarTop(); result = unreadBarTop();
@ -4974,12 +5057,7 @@ void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector<MTPMessage>
_list->messagesReceived(peer, messages); _list->messagesReceived(peer, messages);
if (!_firstLoadRequest) { if (!_firstLoadRequest) {
updateHistoryGeometry(); updateHistoryGeometry();
if (_animActiveTimer.isActive() && _activeAnimMsgId > 0 && _migrated && !_migrated->isEmpty() && _migrated->loadedAtBottom() && _migrated->blocks.back()->items.back()->isGroupMigrate() && _list->historyTop() != _list->historyDrawTop() && _history) { adjustHighlightedMessageToMigrated();
auto animActiveItem = App::histItemById(_history->channelId(), _activeAnimMsgId);
if (animActiveItem && animActiveItem->isGroupMigrate()) {
_activeAnimMsgId = -_migrated->blocks.back()->items.back()->id;
}
}
updateBotKeyboard(); updateBotKeyboard();
} }
} }
@ -6147,36 +6225,6 @@ HistoryItem *HistoryWidget::getItemFromHistoryOrMigrated(MsgId genericMsgId) con
return App::histItemById(_channel, genericMsgId); return App::histItemById(_channel, genericMsgId);
} }
void HistoryWidget::onAnimActiveStep() {
if (!_history || !_activeAnimMsgId || (_activeAnimMsgId < 0 && (!_migrated || -_activeAnimMsgId >= ServerMaxMsgId))) {
return _animActiveTimer.stop();
}
auto item = getItemFromHistoryOrMigrated(_activeAnimMsgId);
if (!item || item->detached()) {
return _animActiveTimer.stop();
}
if (getms() - _animActiveStart > st::activeFadeInDuration + st::activeFadeOutDuration) {
stopAnimActive();
} else {
Ui::repaintHistoryItem(item);
}
}
uint64 HistoryWidget::animActiveTimeStart(const HistoryItem *msg) const {
if (!msg) return 0;
if ((msg->history() == _history && msg->id == _activeAnimMsgId) || (_migrated && msg->history() == _migrated && msg->id == -_activeAnimMsgId)) {
return _animActiveTimer.isActive() ? _animActiveStart : 0;
}
return 0;
}
void HistoryWidget::stopAnimActive() {
_animActiveTimer.stop();
_activeAnimMsgId = 0;
}
SelectedItemSet HistoryWidget::getSelectedItems() const { SelectedItemSet HistoryWidget::getSelectedItems() const {
return _list ? _list->getSelectedItems() : SelectedItemSet(); return _list ? _list->getSelectedItems() : SelectedItemSet();
} }

View file

@ -262,8 +262,8 @@ public:
bool touchScroll(const QPoint &delta); bool touchScroll(const QPoint &delta);
uint64 animActiveTimeStart(const HistoryItem *msg) const; void enqueueMessageHighlight(not_null<HistoryItem*> item);
void stopAnimActive(); TimeMs highlightStartTime(not_null<const HistoryItem*> item) const;
SelectedItemSet getSelectedItems() const; SelectedItemSet getSelectedItems() const;
void itemEdited(HistoryItem *item); void itemEdited(HistoryItem *item);
@ -445,8 +445,6 @@ public slots:
void onForwardSelected(); void onForwardSelected();
void onClearSelected(); void onClearSelected();
void onAnimActiveStep();
void onDraftSaveDelayed(); void onDraftSaveDelayed();
void onDraftSave(bool delayed = false); void onDraftSave(bool delayed = false);
void onCloudDraftSave(); void onCloudDraftSave();
@ -492,6 +490,13 @@ private:
void showNextUnreadMention(); void showNextUnreadMention();
void handlePeerUpdate(); void handlePeerUpdate();
void highlightMessage(MsgId universalMessageId);
void adjustHighlightedMessageToMigrated();
void checkNextHighlight();
void updateHighlightedMessage();
void clearHighlightMessages();
void stopMessageHighlight();
void animationCallback(); void animationCallback();
void updateOverStates(QPoint pos); void updateOverStates(QPoint pos);
void recordStartCallback(); void recordStartCallback();
@ -701,7 +706,7 @@ private:
HistoryItem *getItemFromHistoryOrMigrated(MsgId genericMsgId) const; HistoryItem *getItemFromHistoryOrMigrated(MsgId genericMsgId) const;
void animatedScrollToItem(MsgId msgId); void animatedScrollToItem(MsgId msgId);
void animatedScrollToY(int scrollTo, HistoryItem *attachTo = nullptr); void animatedScrollToY(int scrollTo, HistoryItem *attachTo = nullptr);
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
@ -729,8 +734,6 @@ private:
MsgId _delayedShowAtMsgId = -1; // wtf? MsgId _delayedShowAtMsgId = -1; // wtf?
mtpRequestId _delayedShowAtRequest = 0; mtpRequestId _delayedShowAtRequest = 0;
MsgId _activeAnimMsgId = 0;
object_ptr<Ui::AbstractButton> _backAnimationButton = { nullptr }; object_ptr<Ui::AbstractButton> _backAnimationButton = { nullptr };
object_ptr<Window::TopBarWidget> _topBar; object_ptr<Window::TopBarWidget> _topBar;
object_ptr<Ui::ScrollArea> _scroll; object_ptr<Ui::ScrollArea> _scroll;
@ -846,8 +849,10 @@ private:
QTimer _scrollTimer; QTimer _scrollTimer;
int32 _scrollDelta = 0; int32 _scrollDelta = 0;
QTimer _animActiveTimer; MsgId _highlightedMessageId = 0;
float64 _animActiveStart = 0; std::deque<MsgId> _highlightQueue;
base::Timer _highlightTimer;
TimeMs _highlightStart = 0;
QMap<QPair<History*, SendAction::Type>, mtpRequestId> _sendActionRequests; QMap<QPair<History*, SendAction::Type>, mtpRequestId> _sendActionRequests;
QTimer _sendActionStopTimer; QTimer _sendActionStopTimer;

View file

@ -1529,12 +1529,8 @@ void MainWidget::unreadCountChanged(History *history) {
_history->unreadCountChanged(history); _history->unreadCountChanged(history);
} }
TimeMs MainWidget::animActiveTimeStart(const HistoryItem *msg) const { TimeMs MainWidget::highlightStartTime(not_null<const HistoryItem*> item) const {
return _history->animActiveTimeStart(msg); return _history->highlightStartTime(item);
}
void MainWidget::stopAnimActive() {
_history->stopAnimActive();
} }
void MainWidget::sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo) { void MainWidget::sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo) {

View file

@ -309,8 +309,7 @@ public:
void readServerHistory(History *history, ReadServerHistoryChecks checks = ReadServerHistoryChecks::OnlyIfUnread); void readServerHistory(History *history, ReadServerHistoryChecks checks = ReadServerHistoryChecks::OnlyIfUnread);
void unreadCountChanged(History *history); void unreadCountChanged(History *history);
TimeMs animActiveTimeStart(const HistoryItem *msg) const; TimeMs highlightStartTime(not_null<const HistoryItem*> item) const;
void stopAnimActive();
void sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo); void sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo);
void hideSingleUseKeyboard(PeerData *peer, MsgId replyTo); void hideSingleUseKeyboard(PeerData *peer, MsgId replyTo);

View file

@ -1026,7 +1026,7 @@ void MediaView::onCopy() {
} }
void MediaView::showPhoto(PhotoData *photo, HistoryItem *context) { void MediaView::showPhoto(PhotoData *photo, HistoryItem *context) {
_history = context ? context->history() : nullptr; _history = context ? context->history().get() : nullptr;
_migrated = nullptr; _migrated = nullptr;
if (_history) { if (_history) {
if (_history->peer->migrateFrom()) { if (_history->peer->migrateFrom()) {
@ -1144,7 +1144,7 @@ void MediaView::showPhoto(PhotoData *photo, PeerData *context) {
void MediaView::showDocument(DocumentData *doc, HistoryItem *context) { void MediaView::showDocument(DocumentData *doc, HistoryItem *context) {
_photo = 0; _photo = 0;
_history = context ? context->history() : nullptr; _history = context ? context->history().get() : nullptr;
_migrated = nullptr; _migrated = nullptr;
if (_history) { if (_history) {
if (_history->peer->migrateFrom()) { if (_history->peer->migrateFrom()) {