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

View File

@ -600,9 +600,14 @@ TextSelection shiftSelection(TextSelection selection, uint16 byLength) {
} // namespace internal
HistoryItem::HistoryItem(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime msgDate, int32 from) : HistoryElement()
, id(msgId)
, date(msgDate)
HistoryItem::HistoryItem(
not_null<History*> history,
MsgId id,
MTPDmessage::Flags flags,
QDateTime date,
UserId from) : HistoryElement()
, id(id)
, date(date)
, _history(history)
, _from(from ? App::user(from) : history->peer)
, _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);
History *history() const {
not_null<History*> history() const {
return _history;
}
PeerData *from() const {
@ -921,7 +921,12 @@ public:
~HistoryItem();
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
// a virtual method, it can not be done from constructor.
@ -938,7 +943,7 @@ protected:
void finishEdition(int oldKeyboardTop);
void finishEditionToEmpty();
not_null<History*> _history;
const not_null<History*> _history;
not_null<PeerData*> _from;
HistoryBlock *_block = nullptr;
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) {
int animms = ms - fullAnimMs;
if (animms > st::activeFadeInDuration + st::activeFadeOutDuration) {
App::main()->stopAnimActive();
} else {
auto animms = ms - fullAnimMs;
if (animms < st::activeFadeInDuration + st::activeFadeOutDuration) {
auto top = marginTop();
auto bottom = marginBottom();
auto fill = qMin(top, bottom);

View File

@ -188,16 +188,18 @@ int WideChatWidth() {
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();
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) {
int animms = context.ms - fullAnimMs;
if (animms > st::activeFadeInDuration + st::activeFadeOutDuration) {
App::main()->stopAnimActive();
} else {
auto animms = context.ms - fullAnimMs;
if (animms < st::activeFadeInDuration + st::activeFadeOutDuration) {
auto top = st::msgServiceMargin.top();
auto bottom = st::msgServiceMargin.bottom();
auto fill = qMin(top, bottom);

View File

@ -39,7 +39,11 @@ struct PaintContext {
class ServiceMessagePainter {
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 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);
_animActiveTimer.setSingleShot(false);
connect(&_animActiveTimer, SIGNAL(timeout()), this, SLOT(onAnimActiveStep()));
_highlightTimer.setCallback([this] { updateHighlightedMessage(); });
_membersDropdownShowTimer.setSingleShot(true);
connect(&_membersDropdownShowTimer, SIGNAL(timeout()), this, SLOT(onMembersDropdownShow()));
@ -948,24 +947,108 @@ void HistoryWidget::scrollToAnimationCallback(FullMsgId attachToId) {
}
}
void HistoryWidget::highlightMessage(HistoryItem *context) {
Expects(_list != nullptr);
void HistoryWidget::enqueueMessageHighlight(not_null<HistoryItem*> item) {
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();
_animActiveTimer.start(AnimationTimerDelta);
_activeAnimMsgId = _showAtMsgId;
if (context
&& context->history() == _history
&& context->isGroupMigrate()
void HistoryWidget::highlightMessage(MsgId universalMessageId) {
_highlightStart = getms();
_highlightedMessageId = universalMessageId;
_highlightTimer.callEach(AnimationTimerDelta);
adjustHighlightedMessageToMigrated();
}
void HistoryWidget::adjustHighlightedMessageToMigrated() {
if (_history
&& _highlightTimer.isActive()
&& _highlightedMessageId > 0
&& _migrated
&& !_migrated->isEmpty()
&& _migrated->loadedAtBottom()
&& _migrated->blocks.back()->items.back()->isGroupMigrate()
&& _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 {
auto itemTop = _list->itemTop(item);
Assert(itemTop >= 0);
@ -1644,6 +1727,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
showAtMsgId = ShowAtTheEndMsgId;
}
clearHighlightMessages();
if (_history) {
if (_peer->id == peerId && !reload) {
updateForwarding();
@ -1676,7 +1760,6 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
auto item = getItemFromHistoryOrMigrated(_showAtMsgId);
animatedScrollToY(countInitialScrollTop(), item);
highlightMessage(item);
} else {
historyLoaded();
}
@ -4808,7 +4891,7 @@ int HistoryWidget::countInitialScrollTop() {
return countInitialScrollTop();
} else {
result = itemTopForHighlight(item);
highlightMessage(item);
enqueueMessageHighlight(item);
}
} else if (_history->unreadBar || (_migrated && _migrated->unreadBar)) {
result = unreadBarTop();
@ -4974,12 +5057,7 @@ void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector<MTPMessage>
_list->messagesReceived(peer, messages);
if (!_firstLoadRequest) {
updateHistoryGeometry();
if (_animActiveTimer.isActive() && _activeAnimMsgId > 0 && _migrated && !_migrated->isEmpty() && _migrated->loadedAtBottom() && _migrated->blocks.back()->items.back()->isGroupMigrate() && _list->historyTop() != _list->historyDrawTop() && _history) {
auto animActiveItem = App::histItemById(_history->channelId(), _activeAnimMsgId);
if (animActiveItem && animActiveItem->isGroupMigrate()) {
_activeAnimMsgId = -_migrated->blocks.back()->items.back()->id;
}
}
adjustHighlightedMessageToMigrated();
updateBotKeyboard();
}
}
@ -6147,36 +6225,6 @@ HistoryItem *HistoryWidget::getItemFromHistoryOrMigrated(MsgId genericMsgId) con
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 {
return _list ? _list->getSelectedItems() : SelectedItemSet();
}

View File

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

View File

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

View File

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