mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Show emoji interaction seen status.
This commit is contained in:
parent
4b7f594b0e
commit
34c0d97c54
7 changed files with 215 additions and 20 deletions
|
@ -1618,6 +1618,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_user_action_upload_file" = "{user} is sending a file";
|
"lng_user_action_upload_file" = "{user} is sending a file";
|
||||||
"lng_send_action_choose_sticker" = "choosing a sticker";
|
"lng_send_action_choose_sticker" = "choosing a sticker";
|
||||||
"lng_user_action_choose_sticker" = "{user} is choosing a sticker";
|
"lng_user_action_choose_sticker" = "{user} is choosing a sticker";
|
||||||
|
"lng_user_action_watching_animations" = "watching {emoji} animations";
|
||||||
"lng_unread_bar#one" = "{count} unread message";
|
"lng_unread_bar#one" = "{count} unread message";
|
||||||
"lng_unread_bar#other" = "{count} unread messages";
|
"lng_unread_bar#other" = "{count} unread messages";
|
||||||
"lng_unread_bar_some" = "Unread messages";
|
"lng_unread_bar_some" = "Unread messages";
|
||||||
|
|
|
@ -991,17 +991,11 @@ void Updates::handleSendActionUpdate(
|
||||||
if (!from || !from->isUser() || from->isSelf()) {
|
if (!from || !from->isUser() || from->isSelf()) {
|
||||||
return;
|
return;
|
||||||
} else if (action.type() == mtpc_sendMessageEmojiInteraction) {
|
} else if (action.type() == mtpc_sendMessageEmojiInteraction) {
|
||||||
const auto &data = action.c_sendMessageEmojiInteraction();
|
handleEmojiInteraction(peer, action.c_sendMessageEmojiInteraction());
|
||||||
const auto json = data.vinteraction().match([&](
|
return;
|
||||||
const MTPDdataJSON &data) {
|
} else if (action.type() == mtpc_sendMessageEmojiInteractionSeen) {
|
||||||
return data.vdata().v;
|
const auto &data = action.c_sendMessageEmojiInteractionSeen();
|
||||||
});
|
handleEmojiInteraction(peer, qs(data.vemoticon()));
|
||||||
const auto emoticon = qs(data.vemoticon());
|
|
||||||
handleEmojiInteraction(
|
|
||||||
peer,
|
|
||||||
data.vmsg_id().v,
|
|
||||||
qs(data.vemoticon()),
|
|
||||||
ChatHelpers::EmojiInteractions::Parse(json));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto when = requestingDifference()
|
const auto when = requestingDifference()
|
||||||
|
@ -1015,6 +1009,20 @@ void Updates::handleSendActionUpdate(
|
||||||
when);
|
when);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Updates::handleEmojiInteraction(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
const MTPDsendMessageEmojiInteraction &data) {
|
||||||
|
const auto json = data.vinteraction().match([&](
|
||||||
|
const MTPDdataJSON &data) {
|
||||||
|
return data.vdata().v;
|
||||||
|
});
|
||||||
|
handleEmojiInteraction(
|
||||||
|
peer,
|
||||||
|
data.vmsg_id().v,
|
||||||
|
qs(data.vemoticon()),
|
||||||
|
ChatHelpers::EmojiInteractions::Parse(json));
|
||||||
|
}
|
||||||
|
|
||||||
void Updates::handleSpeakingInCall(
|
void Updates::handleSpeakingInCall(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
PeerId participantPeerId,
|
PeerId participantPeerId,
|
||||||
|
@ -1061,6 +1069,16 @@ void Updates::handleEmojiInteraction(
|
||||||
std::move(bunch));
|
std::move(bunch));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Updates::handleEmojiInteraction(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
const QString &emoticon) {
|
||||||
|
if (session().windows().empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto window = session().windows().front();
|
||||||
|
window->emojiInteractions().seenOutgoing(peer, emoticon);
|
||||||
|
}
|
||||||
|
|
||||||
void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||||
switch (updates.type()) {
|
switch (updates.type()) {
|
||||||
case mtpc_updateShortMessage: {
|
case mtpc_updateShortMessage: {
|
||||||
|
|
|
@ -143,6 +143,9 @@ private:
|
||||||
MsgId rootId,
|
MsgId rootId,
|
||||||
PeerId fromId,
|
PeerId fromId,
|
||||||
const MTPSendMessageAction &action);
|
const MTPSendMessageAction &action);
|
||||||
|
void handleEmojiInteraction(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
const MTPDsendMessageEmojiInteraction &data);
|
||||||
void handleSpeakingInCall(
|
void handleSpeakingInCall(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
PeerId participantPeerId,
|
PeerId participantPeerId,
|
||||||
|
@ -152,6 +155,9 @@ private:
|
||||||
MsgId messageId,
|
MsgId messageId,
|
||||||
const QString &emoticon,
|
const QString &emoticon,
|
||||||
ChatHelpers::EmojiInteractionsBunch bunch);
|
ChatHelpers::EmojiInteractionsBunch bunch);
|
||||||
|
void handleEmojiInteraction(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
const QString &emoticon);
|
||||||
|
|
||||||
const not_null<Main::Session*> _session;
|
const not_null<Main::Session*> _session;
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace {
|
||||||
constexpr auto kMinDelay = crl::time(200);
|
constexpr auto kMinDelay = crl::time(200);
|
||||||
constexpr auto kAccumulateDelay = crl::time(1000);
|
constexpr auto kAccumulateDelay = crl::time(1000);
|
||||||
constexpr auto kAccumulateSeenRequests = kAccumulateDelay;
|
constexpr auto kAccumulateSeenRequests = kAccumulateDelay;
|
||||||
|
constexpr auto kAcceptSeenSinceRequest = 3 * crl::time(1000);
|
||||||
constexpr auto kMaxDelay = 2 * crl::time(1000);
|
constexpr auto kMaxDelay = 2 * crl::time(1000);
|
||||||
constexpr auto kTimeNever = std::numeric_limits<crl::time>::max();
|
constexpr auto kTimeNever = std::numeric_limits<crl::time>::max();
|
||||||
constexpr auto kJsonVersion = 1;
|
constexpr auto kJsonVersion = 1;
|
||||||
|
@ -177,6 +178,21 @@ void EmojiInteractions::startIncoming(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmojiInteractions::seenOutgoing(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
const QString &emoticon) {
|
||||||
|
if (const auto i = _playsSent.find(peer); i != end(_playsSent)) {
|
||||||
|
if (const auto emoji = Ui::Emoji::Find(emoticon)) {
|
||||||
|
if (const auto j = i->second.find(emoji); j != end(i->second)) {
|
||||||
|
const auto last = j->second.lastDoneReceivedAt;
|
||||||
|
if (!last || last + kAcceptSeenSinceRequest > crl::now()) {
|
||||||
|
_seen.fire({ peer, emoji });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto EmojiInteractions::checkAnimations(crl::time now) -> CheckResult {
|
auto EmojiInteractions::checkAnimations(crl::time now) -> CheckResult {
|
||||||
return Combine(
|
return Combine(
|
||||||
checkAnimations(now, _outgoing),
|
checkAnimations(now, _outgoing),
|
||||||
|
@ -254,15 +270,26 @@ void EmojiInteractions::sendAccumulatedOutgoing(
|
||||||
if (bunch.interactions.empty()) {
|
if (bunch.interactions.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_session->api().request(MTPmessages_SetTyping(
|
const auto peer = item->history()->peer;
|
||||||
|
const auto emoji = from->emoji;
|
||||||
|
const auto requestId = _session->api().request(MTPmessages_SetTyping(
|
||||||
MTP_flags(0),
|
MTP_flags(0),
|
||||||
item->history()->peer->input,
|
peer->input,
|
||||||
MTPint(), // top_msg_id
|
MTPint(), // top_msg_id
|
||||||
MTP_sendMessageEmojiInteraction(
|
MTP_sendMessageEmojiInteraction(
|
||||||
MTP_string(from->emoji->text()),
|
MTP_string(emoji->text()),
|
||||||
MTP_int(item->id),
|
MTP_int(item->id),
|
||||||
MTP_dataJSON(MTP_bytes(ToJson(bunch))))
|
MTP_dataJSON(MTP_bytes(ToJson(bunch))))
|
||||||
)).send();
|
)).done([=](const MTPBool &result, mtpRequestId requestId) {
|
||||||
|
auto &sent = _playsSent[peer][emoji];
|
||||||
|
if (sent.lastRequestId == requestId) {
|
||||||
|
sent.lastDoneReceivedAt = crl::now();
|
||||||
|
if (!_checkTimer.isActive()) {
|
||||||
|
_checkTimer.callOnce(kAcceptSeenSinceRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).send();
|
||||||
|
_playsSent[peer][emoji] = PlaySent{ .lastRequestId = requestId };
|
||||||
animations.erase(from, till);
|
animations.erase(from, till);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,6 +342,7 @@ void EmojiInteractions::check(crl::time now) {
|
||||||
now = crl::now();
|
now = crl::now();
|
||||||
}
|
}
|
||||||
checkSeenRequests(now);
|
checkSeenRequests(now);
|
||||||
|
checkSentRequests(now);
|
||||||
const auto result1 = checkAnimations(now);
|
const auto result1 = checkAnimations(now);
|
||||||
const auto result2 = checkAccumulated(now);
|
const auto result2 = checkAccumulated(now);
|
||||||
const auto result = Combine(result1, result2);
|
const auto result = Combine(result1, result2);
|
||||||
|
@ -323,6 +351,8 @@ void EmojiInteractions::check(crl::time now) {
|
||||||
_checkTimer.callOnce(result.nextCheckAt - now);
|
_checkTimer.callOnce(result.nextCheckAt - now);
|
||||||
} else if (!_playStarted.empty()) {
|
} else if (!_playStarted.empty()) {
|
||||||
_checkTimer.callOnce(kAccumulateSeenRequests);
|
_checkTimer.callOnce(kAccumulateSeenRequests);
|
||||||
|
} else if (!_playsSent.empty()) {
|
||||||
|
_checkTimer.callOnce(kAcceptSeenSinceRequest);
|
||||||
}
|
}
|
||||||
setWaitingForDownload(result.waitingForDownload);
|
setWaitingForDownload(result.waitingForDownload);
|
||||||
}
|
}
|
||||||
|
@ -344,6 +374,24 @@ void EmojiInteractions::checkSeenRequests(crl::time now) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmojiInteractions::checkSentRequests(crl::time now) {
|
||||||
|
for (auto i = begin(_playsSent); i != end(_playsSent);) {
|
||||||
|
for (auto j = begin(i->second); j != end(i->second);) {
|
||||||
|
const auto last = j->second.lastDoneReceivedAt;
|
||||||
|
if (last && last + kAcceptSeenSinceRequest <= now) {
|
||||||
|
j = i->second.erase(j);
|
||||||
|
} else {
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i->second.empty()) {
|
||||||
|
i = _playsSent.erase(i);
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmojiInteractions::setWaitingForDownload(bool waiting) {
|
void EmojiInteractions::setWaitingForDownload(bool waiting) {
|
||||||
if (_waitingForDownload == waiting) {
|
if (_waitingForDownload == waiting) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -43,6 +43,11 @@ struct EmojiInteractionsBunch {
|
||||||
std::vector<Single> interactions;
|
std::vector<Single> interactions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct EmojiInteractionSeen {
|
||||||
|
not_null<PeerData*> peer;
|
||||||
|
not_null<EmojiPtr> emoji;
|
||||||
|
};
|
||||||
|
|
||||||
class EmojiInteractions final {
|
class EmojiInteractions final {
|
||||||
public:
|
public:
|
||||||
explicit EmojiInteractions(not_null<Main::Session*> session);
|
explicit EmojiInteractions(not_null<Main::Session*> session);
|
||||||
|
@ -57,6 +62,11 @@ public:
|
||||||
const QString &emoticon,
|
const QString &emoticon,
|
||||||
EmojiInteractionsBunch &&bunch);
|
EmojiInteractionsBunch &&bunch);
|
||||||
|
|
||||||
|
void seenOutgoing(not_null<PeerData*> peer, const QString &emoticon);
|
||||||
|
[[nodiscard]] rpl::producer<EmojiInteractionSeen> seen() const {
|
||||||
|
return _seen.events();
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<PlayRequest> playRequests() const {
|
[[nodiscard]] rpl::producer<PlayRequest> playRequests() const {
|
||||||
return _playRequests.events();
|
return _playRequests.events();
|
||||||
}
|
}
|
||||||
|
@ -68,7 +78,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Animation {
|
struct Animation {
|
||||||
EmojiPtr emoji;
|
not_null<EmojiPtr> emoji;
|
||||||
not_null<DocumentData*> document;
|
not_null<DocumentData*> document;
|
||||||
std::shared_ptr<Data::DocumentMedia> media;
|
std::shared_ptr<Data::DocumentMedia> media;
|
||||||
crl::time scheduledAt = 0;
|
crl::time scheduledAt = 0;
|
||||||
|
@ -76,6 +86,10 @@ private:
|
||||||
bool incoming = false;
|
bool incoming = false;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
};
|
};
|
||||||
|
struct PlaySent {
|
||||||
|
mtpRequestId lastRequestId = 0;
|
||||||
|
crl::time lastDoneReceivedAt = 0;
|
||||||
|
};
|
||||||
struct CheckResult {
|
struct CheckResult {
|
||||||
crl::time nextCheckAt = 0;
|
crl::time nextCheckAt = 0;
|
||||||
bool waitingForDownload = false;
|
bool waitingForDownload = false;
|
||||||
|
@ -98,6 +112,7 @@ private:
|
||||||
void setWaitingForDownload(bool waiting);
|
void setWaitingForDownload(bool waiting);
|
||||||
|
|
||||||
void checkSeenRequests(crl::time now);
|
void checkSeenRequests(crl::time now);
|
||||||
|
void checkSentRequests(crl::time now);
|
||||||
void checkEdition(
|
void checkEdition(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
base::flat_map<not_null<HistoryItem*>, std::vector<Animation>> &map);
|
base::flat_map<not_null<HistoryItem*>, std::vector<Animation>> &map);
|
||||||
|
@ -111,6 +126,10 @@ private:
|
||||||
base::flat_map<
|
base::flat_map<
|
||||||
not_null<PeerData*>,
|
not_null<PeerData*>,
|
||||||
base::flat_map<QString, crl::time>> _playStarted;
|
base::flat_map<QString, crl::time>> _playStarted;
|
||||||
|
base::flat_map<
|
||||||
|
not_null<PeerData*>,
|
||||||
|
base::flat_map<not_null<EmojiPtr>, PlaySent>> _playsSent;
|
||||||
|
rpl::event_stream<EmojiInteractionSeen> _seen;
|
||||||
|
|
||||||
bool _waitingForDownload = false;
|
bool _waitingForDownload = false;
|
||||||
rpl::lifetime _downloadCheckLifetime;
|
rpl::lifetime _downloadCheckLifetime;
|
||||||
|
|
|
@ -29,6 +29,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/effects/radial_animation.h"
|
#include "ui/effects/radial_animation.h"
|
||||||
#include "ui/toasts/common_toasts.h"
|
#include "ui/toasts/common_toasts.h"
|
||||||
#include "ui/boxes/report_box.h" // Ui::ReportReason
|
#include "ui/boxes/report_box.h" // Ui::ReportReason
|
||||||
|
#include "ui/text/text.h"
|
||||||
|
#include "ui/text/text_options.h"
|
||||||
#include "ui/special_buttons.h"
|
#include "ui/special_buttons.h"
|
||||||
#include "ui/unread_badge.h"
|
#include "ui/unread_badge.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
|
@ -45,6 +47,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_send_action.h"
|
#include "data/data_send_action.h"
|
||||||
|
#include "chat_helpers/emoji_interactions.h"
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "support/support_helper.h"
|
#include "support/support_helper.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
|
@ -54,6 +57,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "styles/style_info.h"
|
#include "styles/style_info.h"
|
||||||
|
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kEmojiInteractionSeenDuration = 3 * crl::time(1000);
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
struct TopBarWidget::EmojiInteractionSeenAnimation {
|
||||||
|
Ui::SendActionAnimation animation;
|
||||||
|
Ui::Animations::Basic scheduler;
|
||||||
|
Ui::Text::String text = { st::dialogsTextWidthMin };
|
||||||
|
crl::time till = 0;
|
||||||
|
};
|
||||||
|
|
||||||
TopBarWidget::TopBarWidget(
|
TopBarWidget::TopBarWidget(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
|
@ -402,6 +417,7 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto now = crl::now();
|
||||||
const auto history = _activeChat.key.history();
|
const auto history = _activeChat.key.history();
|
||||||
const auto folder = _activeChat.key.folder();
|
const auto folder = _activeChat.key.folder();
|
||||||
if (folder
|
if (folder
|
||||||
|
@ -442,14 +458,14 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
||||||
|
|
||||||
p.setFont(st::dialogsTextFont);
|
p.setFont(st::dialogsTextFont);
|
||||||
if (!paintConnectingState(p, nameleft, statustop, width())
|
if (!paintConnectingState(p, nameleft, statustop, width())
|
||||||
&& !_sendAction->paint(
|
&& !paintSendAction(
|
||||||
p,
|
p,
|
||||||
nameleft,
|
nameleft,
|
||||||
statustop,
|
statustop,
|
||||||
availableWidth,
|
availableWidth,
|
||||||
width(),
|
width(),
|
||||||
st::historyStatusFgTyping,
|
st::historyStatusFgTyping,
|
||||||
crl::now())) {
|
now)) {
|
||||||
p.setPen(st::historyStatusFg);
|
p.setPen(st::historyStatusFg);
|
||||||
p.drawTextLeft(nameleft, statustop, width(), _customTitleText);
|
p.drawTextLeft(nameleft, statustop, width(), _customTitleText);
|
||||||
}
|
}
|
||||||
|
@ -481,19 +497,48 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
||||||
|
|
||||||
p.setFont(st::dialogsTextFont);
|
p.setFont(st::dialogsTextFont);
|
||||||
if (!paintConnectingState(p, nameleft, statustop, width())
|
if (!paintConnectingState(p, nameleft, statustop, width())
|
||||||
&& !_sendAction->paint(
|
&& !paintSendAction(
|
||||||
p,
|
p,
|
||||||
nameleft,
|
nameleft,
|
||||||
statustop,
|
statustop,
|
||||||
availableWidth,
|
availableWidth,
|
||||||
width(),
|
width(),
|
||||||
st::historyStatusFgTyping,
|
st::historyStatusFgTyping,
|
||||||
crl::now())) {
|
now)) {
|
||||||
paintStatus(p, nameleft, statustop, availableWidth, width());
|
paintStatus(p, nameleft, statustop, availableWidth, width());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TopBarWidget::paintSendAction(
|
||||||
|
Painter &p,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int availableWidth,
|
||||||
|
int outerWidth,
|
||||||
|
style::color fg,
|
||||||
|
crl::time now) {
|
||||||
|
const auto seen = _emojiInteractionSeen.get();
|
||||||
|
if (!seen || seen->till <= now) {
|
||||||
|
return _sendAction->paint(p, x, y, availableWidth, outerWidth, fg, now);
|
||||||
|
}
|
||||||
|
const auto animationWidth = seen->animation.width();
|
||||||
|
const auto extraAnimationWidth = animationWidth * 2;
|
||||||
|
seen->animation.paint(
|
||||||
|
p,
|
||||||
|
fg,
|
||||||
|
x,
|
||||||
|
y + st::normalFont->ascent,
|
||||||
|
outerWidth,
|
||||||
|
now);
|
||||||
|
|
||||||
|
x += animationWidth;
|
||||||
|
availableWidth -= extraAnimationWidth;
|
||||||
|
p.setPen(fg);
|
||||||
|
seen->text.drawElided(p, x, y, availableWidth);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool TopBarWidget::paintConnectingState(
|
bool TopBarWidget::paintConnectingState(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
int left,
|
int left,
|
||||||
|
@ -597,6 +642,7 @@ void TopBarWidget::setActiveChat(
|
||||||
update();
|
update();
|
||||||
|
|
||||||
if (peerChanged) {
|
if (peerChanged) {
|
||||||
|
_emojiInteractionSeen = nullptr;
|
||||||
_activeChatLifetime.destroy();
|
_activeChatLifetime.destroy();
|
||||||
if (const auto history = _activeChat.key.history()) {
|
if (const auto history = _activeChat.key.history()) {
|
||||||
session().changes().peerFlagsValue(
|
session().changes().peerFlagsValue(
|
||||||
|
@ -615,6 +661,14 @@ void TopBarWidget::setActiveChat(
|
||||||
updateControlsVisibility();
|
updateControlsVisibility();
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
}, _activeChatLifetime);
|
}, _activeChatLifetime);
|
||||||
|
|
||||||
|
using InteractionSeen = ChatHelpers::EmojiInteractionSeen;
|
||||||
|
_controller->emojiInteractions().seen(
|
||||||
|
) | rpl::filter([=](const InteractionSeen &seen) {
|
||||||
|
return (seen.peer == history->peer);
|
||||||
|
}) | rpl::start_with_next([=](const InteractionSeen &seen) {
|
||||||
|
handleEmojiInteractionSeen(seen.emoji->text());
|
||||||
|
}, lifetime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateUnreadBadge();
|
updateUnreadBadge();
|
||||||
|
@ -628,6 +682,42 @@ void TopBarWidget::setActiveChat(
|
||||||
refreshUnreadBadge();
|
refreshUnreadBadge();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TopBarWidget::handleEmojiInteractionSeen(const QString &emoticon) {
|
||||||
|
auto seen = _emojiInteractionSeen.get();
|
||||||
|
if (!seen) {
|
||||||
|
_emojiInteractionSeen
|
||||||
|
= std::make_unique<EmojiInteractionSeenAnimation>();
|
||||||
|
seen = _emojiInteractionSeen.get();
|
||||||
|
seen->animation.start(Ui::SendActionAnimation::Type::ChooseSticker);
|
||||||
|
seen->scheduler.init([=] {
|
||||||
|
if (seen->till <= crl::now()) {
|
||||||
|
crl::on_main(this, [=] {
|
||||||
|
if (_emojiInteractionSeen
|
||||||
|
&& _emojiInteractionSeen->till <= crl::now()) {
|
||||||
|
_emojiInteractionSeen = nullptr;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const auto animationWidth = seen->animation.width();
|
||||||
|
const auto skip = st::topBarArrowPadding.bottom();
|
||||||
|
update(
|
||||||
|
_leftTaken,
|
||||||
|
st::topBarHeight - skip - st::dialogsTextFont->height,
|
||||||
|
seen->animation.width(),
|
||||||
|
st::dialogsTextFont->height);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
seen->scheduler.start();
|
||||||
|
}
|
||||||
|
seen->till = crl::now() + kEmojiInteractionSeenDuration;
|
||||||
|
seen->text.setText(
|
||||||
|
st::dialogsTextStyle,
|
||||||
|
tr::lng_user_action_watching_animations(tr::now, lt_emoji, emoticon),
|
||||||
|
Ui::NameTextOptions());
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
void TopBarWidget::setCustomTitle(const QString &title) {
|
void TopBarWidget::setCustomTitle(const QString &title) {
|
||||||
if (_customTitleText != title) {
|
if (_customTitleText != title) {
|
||||||
_customTitleText = title;
|
_customTitleText = title;
|
||||||
|
|
|
@ -95,6 +95,8 @@ protected:
|
||||||
int resizeGetHeight(int newWidth) override;
|
int resizeGetHeight(int newWidth) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct EmojiInteractionSeenAnimation;
|
||||||
|
|
||||||
void refreshInfoButton();
|
void refreshInfoButton();
|
||||||
void refreshLang();
|
void refreshLang();
|
||||||
void updateSearchVisibility();
|
void updateSearchVisibility();
|
||||||
|
@ -109,6 +111,16 @@ private:
|
||||||
void showMenu();
|
void showMenu();
|
||||||
void toggleInfoSection();
|
void toggleInfoSection();
|
||||||
|
|
||||||
|
void handleEmojiInteractionSeen(const QString &emoticon);
|
||||||
|
bool paintSendAction(
|
||||||
|
Painter &p,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int availableWidth,
|
||||||
|
int outerWidth,
|
||||||
|
style::color fg,
|
||||||
|
crl::time now);
|
||||||
|
|
||||||
void updateConnectingState();
|
void updateConnectingState();
|
||||||
void updateAdaptiveLayout();
|
void updateAdaptiveLayout();
|
||||||
int countSelectedButtonsTop(float64 selectedShown);
|
int countSelectedButtonsTop(float64 selectedShown);
|
||||||
|
@ -140,6 +152,7 @@ private:
|
||||||
const not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
ActiveChat _activeChat;
|
ActiveChat _activeChat;
|
||||||
QString _customTitleText;
|
QString _customTitleText;
|
||||||
|
std::unique_ptr<EmojiInteractionSeenAnimation> _emojiInteractionSeen;
|
||||||
rpl::lifetime _activeChatLifetime;
|
rpl::lifetime _activeChatLifetime;
|
||||||
|
|
||||||
int _selectedCount = 0;
|
int _selectedCount = 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue