mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Notify about published scheduled messages.
This commit is contained in:
parent
3b76a908a4
commit
0a4f91a53d
21 changed files with 423 additions and 179 deletions
|
@ -1188,6 +1188,14 @@ rpl::producer<not_null<const ViewElement*>> Session::viewLayoutChanged() const {
|
||||||
return _viewLayoutChanges.events();
|
return _viewLayoutChanges.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Session::notifyUnreadItemAdded(not_null<HistoryItem*> item) {
|
||||||
|
_unreadItemAdded.fire_copy(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<not_null<HistoryItem*>> Session::unreadItemAdded() const {
|
||||||
|
return _unreadItemAdded.events();
|
||||||
|
}
|
||||||
|
|
||||||
void Session::changeMessageId(ChannelId channel, MsgId wasId, MsgId nowId) {
|
void Session::changeMessageId(ChannelId channel, MsgId wasId, MsgId nowId) {
|
||||||
const auto list = messagesListForInsert(channel);
|
const auto list = messagesListForInsert(channel);
|
||||||
auto i = list->find(wasId);
|
auto i = list->find(wasId);
|
||||||
|
|
|
@ -192,6 +192,8 @@ public:
|
||||||
[[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemLayoutChanged() const;
|
[[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemLayoutChanged() const;
|
||||||
void notifyViewLayoutChange(not_null<const ViewElement*> view);
|
void notifyViewLayoutChange(not_null<const ViewElement*> view);
|
||||||
[[nodiscard]] rpl::producer<not_null<const ViewElement*>> viewLayoutChanged() const;
|
[[nodiscard]] rpl::producer<not_null<const ViewElement*>> viewLayoutChanged() const;
|
||||||
|
void notifyUnreadItemAdded(not_null<HistoryItem*> item);
|
||||||
|
[[nodiscard]] rpl::producer<not_null<HistoryItem*>> unreadItemAdded() const;
|
||||||
void requestItemRepaint(not_null<const HistoryItem*> item);
|
void requestItemRepaint(not_null<const HistoryItem*> item);
|
||||||
[[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemRepaintRequest() const;
|
[[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemRepaintRequest() const;
|
||||||
void requestViewRepaint(not_null<const ViewElement*> view);
|
void requestViewRepaint(not_null<const ViewElement*> view);
|
||||||
|
@ -841,6 +843,7 @@ private:
|
||||||
rpl::event_stream<IdChange> _itemIdChanges;
|
rpl::event_stream<IdChange> _itemIdChanges;
|
||||||
rpl::event_stream<not_null<const HistoryItem*>> _itemLayoutChanges;
|
rpl::event_stream<not_null<const HistoryItem*>> _itemLayoutChanges;
|
||||||
rpl::event_stream<not_null<const ViewElement*>> _viewLayoutChanges;
|
rpl::event_stream<not_null<const ViewElement*>> _viewLayoutChanges;
|
||||||
|
rpl::event_stream<not_null<HistoryItem*>> _unreadItemAdded;
|
||||||
rpl::event_stream<not_null<const HistoryItem*>> _itemRepaintRequest;
|
rpl::event_stream<not_null<const HistoryItem*>> _itemRepaintRequest;
|
||||||
rpl::event_stream<not_null<const ViewElement*>> _viewRepaintRequest;
|
rpl::event_stream<not_null<const ViewElement*>> _viewRepaintRequest;
|
||||||
rpl::event_stream<not_null<const HistoryItem*>> _itemResizeRequest;
|
rpl::event_stream<not_null<const HistoryItem*>> _itemResizeRequest;
|
||||||
|
|
|
@ -1242,19 +1242,28 @@ void History::newItemAdded(not_null<HistoryItem*> item) {
|
||||||
from->madeAction(item->date());
|
from->madeAction(item->date());
|
||||||
}
|
}
|
||||||
item->contributeToSlowmode();
|
item->contributeToSlowmode();
|
||||||
if (item->out()) {
|
if (item->showNotification()) {
|
||||||
|
_notifications.push_back(item);
|
||||||
|
owner().notifyUnreadItemAdded(item);
|
||||||
|
const auto stillShow = item->showNotification();
|
||||||
|
if (stillShow) {
|
||||||
|
session().notifications().schedule(item);
|
||||||
|
if (!item->out() && item->unread()) {
|
||||||
|
if (unreadCountKnown()) {
|
||||||
|
setUnreadCount(unreadCount() + 1);
|
||||||
|
} else {
|
||||||
|
session().api().requestDialogEntry(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (item->out()) {
|
||||||
destroyUnreadBar();
|
destroyUnreadBar();
|
||||||
if (!item->unread()) {
|
|
||||||
outboxRead(item);
|
|
||||||
}
|
|
||||||
} else if (item->unread()) {
|
|
||||||
if (!isChannel() || peer->asChannel()->amIn()) {
|
|
||||||
_notifications.push_back(item);
|
|
||||||
App::main()->newUnreadMsg(this, item);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
inboxRead(item);
|
inboxRead(item);
|
||||||
}
|
}
|
||||||
|
if (item->out() && !item->unread()) {
|
||||||
|
outboxRead(item);
|
||||||
|
}
|
||||||
if (!folderKnown()) {
|
if (!folderKnown()) {
|
||||||
session().api().requestDialogEntry(this);
|
session().api().requestDialogEntry(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -367,6 +367,12 @@ void HistoryItem::addLogEntryOriginal(
|
||||||
content);
|
content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PeerData *HistoryItem::specialNotificationPeer() const {
|
||||||
|
return (mentionsMe() && !_history->peer->isUser())
|
||||||
|
? from().get()
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
UserData *HistoryItem::viaBot() const {
|
UserData *HistoryItem::viaBot() const {
|
||||||
if (const auto via = Get<HistoryMessageVia>()) {
|
if (const auto via = Get<HistoryMessageVia>()) {
|
||||||
return via->bot;
|
return via->bot;
|
||||||
|
@ -383,7 +389,22 @@ UserData *HistoryItem::getMessageBot() const {
|
||||||
bot = history()->peer->asUser();
|
bot = history()->peer->asUser();
|
||||||
}
|
}
|
||||||
return (bot && bot->isBot()) ? bot : nullptr;
|
return (bot && bot->isBot()) ? bot : nullptr;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
bool HistoryItem::isHistoryEntry() const {
|
||||||
|
return IsServerMsgId(id)
|
||||||
|
|| (_clientFlags & MTPDmessage_ClientFlag::f_local_history_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HistoryItem::isFromScheduled() const {
|
||||||
|
return isHistoryEntry()
|
||||||
|
&& (_flags & MTPDmessage::Flag::f_from_scheduled);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HistoryItem::isScheduled() const {
|
||||||
|
return !isHistoryEntry()
|
||||||
|
&& (_flags & MTPDmessage::Flag::f_from_scheduled);
|
||||||
|
}
|
||||||
|
|
||||||
void HistoryItem::destroy() {
|
void HistoryItem::destroy() {
|
||||||
_history->owner().destroyMessage(this);
|
_history->owner().destroyMessage(this);
|
||||||
|
@ -737,6 +758,14 @@ bool HistoryItem::unread() const {
|
||||||
return (_clientFlags & MTPDmessage_ClientFlag::f_clientside_unread);
|
return (_clientFlags & MTPDmessage_ClientFlag::f_clientside_unread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HistoryItem::showNotification() const {
|
||||||
|
const auto channel = _history->peer->asChannel();
|
||||||
|
if (channel && !channel->amIn()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return out() ? isFromScheduled() : unread();
|
||||||
|
}
|
||||||
|
|
||||||
void HistoryItem::markClientSideAsRead() {
|
void HistoryItem::markClientSideAsRead() {
|
||||||
_clientFlags &= ~MTPDmessage_ClientFlag::f_clientside_unread;
|
_clientFlags &= ~MTPDmessage_ClientFlag::f_clientside_unread;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,28 +75,20 @@ public:
|
||||||
virtual MsgId dependencyMsgId() const {
|
virtual MsgId dependencyMsgId() const {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
virtual bool notificationReady() const {
|
[[nodiscard]] virtual bool notificationReady() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] PeerData *specialNotificationPeer() const;
|
||||||
virtual void applyGroupAdminChanges(
|
virtual void applyGroupAdminChanges(
|
||||||
const base::flat_set<UserId> &changes) {
|
const base::flat_set<UserId> &changes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
UserData *viaBot() const;
|
[[nodiscard]] UserData *viaBot() const;
|
||||||
UserData *getMessageBot() const;
|
[[nodiscard]] UserData *getMessageBot() const;
|
||||||
|
[[nodiscard]] bool isHistoryEntry() const;
|
||||||
|
[[nodiscard]] bool isFromScheduled() const;
|
||||||
|
[[nodiscard]] bool isScheduled() const;
|
||||||
|
|
||||||
[[nodiscard]] bool isHistoryEntry() const {
|
|
||||||
return IsServerMsgId(id)
|
|
||||||
|| (_clientFlags & MTPDmessage_ClientFlag::f_local_history_entry);
|
|
||||||
}
|
|
||||||
[[nodiscard]] bool isFromScheduled() const {
|
|
||||||
return isHistoryEntry()
|
|
||||||
&& (_flags & MTPDmessage::Flag::f_from_scheduled);
|
|
||||||
}
|
|
||||||
[[nodiscard]] bool isScheduled() const {
|
|
||||||
return !isHistoryEntry()
|
|
||||||
&& (_flags & MTPDmessage::Flag::f_from_scheduled);
|
|
||||||
}
|
|
||||||
void addLogEntryOriginal(
|
void addLogEntryOriginal(
|
||||||
WebPageId localId,
|
WebPageId localId,
|
||||||
const QString &label,
|
const QString &label,
|
||||||
|
@ -123,6 +115,7 @@ public:
|
||||||
return _flags & MTPDmessage::Flag::f_out;
|
return _flags & MTPDmessage::Flag::f_out;
|
||||||
}
|
}
|
||||||
[[nodiscard]] bool unread() const;
|
[[nodiscard]] bool unread() const;
|
||||||
|
[[nodiscard]] bool showNotification() const;
|
||||||
void markClientSideAsRead();
|
void markClientSideAsRead();
|
||||||
[[nodiscard]] bool mentionsMe() const;
|
[[nodiscard]] bool mentionsMe() const;
|
||||||
[[nodiscard]] bool isUnreadMention() const;
|
[[nodiscard]] bool isUnreadMention() const;
|
||||||
|
|
|
@ -1302,7 +1302,12 @@ void HistoryMessage::dependencyItemRemoved(HistoryItem *dependency) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString HistoryMessage::notificationHeader() const {
|
QString HistoryMessage::notificationHeader() const {
|
||||||
return (!_history->peer->isUser() && !isPost()) ? from()->name : QString();
|
if (out() && isFromScheduled()) {
|
||||||
|
return tr::lng_from_you(tr::now);
|
||||||
|
} else if (!_history->peer->isUser() && !isPost()) {
|
||||||
|
return App::peerName(from());
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<HistoryView::Element> HistoryMessage::createView(
|
std::unique_ptr<HistoryView::Element> HistoryMessage::createView(
|
||||||
|
|
|
@ -455,6 +455,12 @@ HistoryWidget::HistoryWidget(
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
session().data().unreadItemAdded(
|
||||||
|
) | rpl::start_with_next([=](not_null<HistoryItem*> item) {
|
||||||
|
unreadMessageAdded(item);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
session().data().itemRemoved(
|
session().data().itemRemoved(
|
||||||
) | rpl::start_with_next([=](not_null<const HistoryItem*> item) {
|
) | rpl::start_with_next([=](not_null<const HistoryItem*> item) {
|
||||||
itemRemoved(item);
|
itemRemoved(item);
|
||||||
|
@ -2225,34 +2231,28 @@ void HistoryWidget::destroyUnreadBar() {
|
||||||
if (_migrated) _migrated->destroyUnreadBar();
|
if (_migrated) _migrated->destroyUnreadBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::newUnreadMsg(
|
void HistoryWidget::unreadMessageAdded(not_null<HistoryItem*> item) {
|
||||||
not_null<History*> history,
|
if (_history != item->history()) {
|
||||||
not_null<HistoryItem*> item) {
|
return;
|
||||||
if (_history == history) {
|
}
|
||||||
// If we get here in non-resized state we can't rely on results of
|
|
||||||
// doWeReadServerHistory() and mark chat as read.
|
|
||||||
// If we receive N messages being not at bottom:
|
|
||||||
// - on first message we set unreadcount += 1, firstUnreadMessage.
|
|
||||||
// - on second we get wrong doWeReadServerHistory() and read both.
|
|
||||||
session().data().sendHistoryChangeNotifications();
|
|
||||||
|
|
||||||
if (_scroll->scrollTop() + 1 > _scroll->scrollTopMax()) {
|
// If we get here in non-resized state we can't rely on results of
|
||||||
destroyUnreadBar();
|
// doWeReadServerHistory() and mark chat as read.
|
||||||
}
|
// If we receive N messages being not at bottom:
|
||||||
if (App::wnd()->doWeReadServerHistory()) {
|
// - on first message we set unreadcount += 1, firstUnreadMessage.
|
||||||
if (item->isUnreadMention() && !item->isUnreadMedia()) {
|
// - on second we get wrong doWeReadServerHistory() and read both.
|
||||||
session().api().markMediaRead(item);
|
session().data().sendHistoryChangeNotifications();
|
||||||
}
|
|
||||||
session().api().readServerHistoryForce(history);
|
if (_scroll->scrollTop() + 1 > _scroll->scrollTopMax()) {
|
||||||
return;
|
destroyUnreadBar();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
session().notifications().schedule(history, item);
|
if (!App::wnd()->doWeReadServerHistory()) {
|
||||||
if (history->unreadCountKnown()) {
|
return;
|
||||||
history->setUnreadCount(history->unreadCount() + 1);
|
|
||||||
} else {
|
|
||||||
session().api().requestDialogEntry(history);
|
|
||||||
}
|
}
|
||||||
|
if (item->isUnreadMention() && !item->isUnreadMedia()) {
|
||||||
|
session().api().markMediaRead(item);
|
||||||
|
}
|
||||||
|
session().api().readServerHistoryForce(_history);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::historyToDown(History *history) {
|
void HistoryWidget::historyToDown(History *history) {
|
||||||
|
|
|
@ -124,9 +124,6 @@ public:
|
||||||
void firstLoadMessages();
|
void firstLoadMessages();
|
||||||
void delayedShowAt(MsgId showAtMsgId);
|
void delayedShowAt(MsgId showAtMsgId);
|
||||||
|
|
||||||
void newUnreadMsg(
|
|
||||||
not_null<History*> history,
|
|
||||||
not_null<HistoryItem*> item);
|
|
||||||
void historyToDown(History *history);
|
void historyToDown(History *history);
|
||||||
|
|
||||||
QRect historyRect() const;
|
QRect historyRect() const;
|
||||||
|
@ -423,6 +420,7 @@ private:
|
||||||
void historyDownAnimationFinish();
|
void historyDownAnimationFinish();
|
||||||
void unreadMentionsAnimationFinish();
|
void unreadMentionsAnimationFinish();
|
||||||
void sendButtonClicked();
|
void sendButtonClicked();
|
||||||
|
void unreadMessageAdded(not_null<HistoryItem*> item);
|
||||||
|
|
||||||
bool canSendFiles(not_null<const QMimeData*> data) const;
|
bool canSendFiles(not_null<const QMimeData*> data) const;
|
||||||
bool confirmSendingFiles(
|
bool confirmSendingFiles(
|
||||||
|
|
|
@ -2198,12 +2198,6 @@ void MainWidget::dialogsToUp() {
|
||||||
_dialogs->jumpToTop();
|
_dialogs->jumpToTop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::newUnreadMsg(
|
|
||||||
not_null<History*> history,
|
|
||||||
not_null<HistoryItem*> item) {
|
|
||||||
_history->newUnreadMsg(history, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWidget::markActiveHistoryAsRead() {
|
void MainWidget::markActiveHistoryAsRead() {
|
||||||
if (const auto activeHistory = _history->history()) {
|
if (const auto activeHistory = _history->history()) {
|
||||||
session().api().readServerHistory(activeHistory);
|
session().api().readServerHistory(activeHistory);
|
||||||
|
|
|
@ -146,9 +146,6 @@ public:
|
||||||
bool deleteChannelFailed(const RPCError &error);
|
bool deleteChannelFailed(const RPCError &error);
|
||||||
void historyToDown(History *hist);
|
void historyToDown(History *hist);
|
||||||
void dialogsToUp();
|
void dialogsToUp();
|
||||||
void newUnreadMsg(
|
|
||||||
not_null<History*> history,
|
|
||||||
not_null<HistoryItem*> item);
|
|
||||||
void markActiveHistoryAsRead();
|
void markActiveHistoryAsRead();
|
||||||
|
|
||||||
PeerData *peer();
|
PeerData *peer();
|
||||||
|
|
|
@ -304,7 +304,14 @@ public:
|
||||||
|
|
||||||
void init(Manager *manager);
|
void init(Manager *manager);
|
||||||
|
|
||||||
void showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton);
|
void showNotification(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
MsgId msgId,
|
||||||
|
const QString &title,
|
||||||
|
const QString &subtitle,
|
||||||
|
const QString &msg,
|
||||||
|
bool hideNameAndPhoto,
|
||||||
|
bool hideReplyButton);
|
||||||
void clearAll();
|
void clearAll();
|
||||||
void clearFromHistory(History *history);
|
void clearFromHistory(History *history);
|
||||||
void clearNotification(PeerId peerId, MsgId msgId);
|
void clearNotification(PeerId peerId, MsgId msgId);
|
||||||
|
@ -384,7 +391,14 @@ QString Manager::Private::escapeNotificationText(const QString &text) const {
|
||||||
return _markupSupported ? escapeHtml(text) : text;
|
return _markupSupported ? escapeHtml(text) : text;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::Private::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
void Manager::Private::showNotification(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
MsgId msgId,
|
||||||
|
const QString &title,
|
||||||
|
const QString &subtitle,
|
||||||
|
const QString &msg,
|
||||||
|
bool hideNameAndPhoto,
|
||||||
|
bool hideReplyButton) {
|
||||||
auto titleText = escapeNotificationText(title);
|
auto titleText = escapeNotificationText(title);
|
||||||
auto subtitleText = escapeNotificationText(subtitle);
|
auto subtitleText = escapeNotificationText(subtitle);
|
||||||
auto msgText = escapeNotificationText(msg);
|
auto msgText = escapeNotificationText(msg);
|
||||||
|
@ -537,8 +551,22 @@ bool Manager::hasActionsSupport() const {
|
||||||
|
|
||||||
Manager::~Manager() = default;
|
Manager::~Manager() = default;
|
||||||
|
|
||||||
void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
void Manager::doShowNativeNotification(
|
||||||
_private->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton);
|
not_null<PeerData*> peer,
|
||||||
|
MsgId msgId,
|
||||||
|
const QString &title,
|
||||||
|
const QString &subtitle,
|
||||||
|
const QString &msg,
|
||||||
|
bool hideNameAndPhoto,
|
||||||
|
bool hideReplyButton) {
|
||||||
|
_private->showNotification(
|
||||||
|
peer,
|
||||||
|
msgId,
|
||||||
|
title,
|
||||||
|
subtitle,
|
||||||
|
msg,
|
||||||
|
hideNameAndPhoto,
|
||||||
|
hideReplyButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::doClearAllFast() {
|
void Manager::doClearAllFast() {
|
||||||
|
|
|
@ -36,7 +36,14 @@ public:
|
||||||
~Manager();
|
~Manager();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) override;
|
void doShowNativeNotification(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
MsgId msgId,
|
||||||
|
const QString &title,
|
||||||
|
const QString &subtitle,
|
||||||
|
const QString &msg,
|
||||||
|
bool hideNameAndPhoto,
|
||||||
|
bool hideReplyButton) override;
|
||||||
void doClearAllFast() override;
|
void doClearAllFast() override;
|
||||||
void doClearFromHistory(History *history) override;
|
void doClearFromHistory(History *history) override;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,14 @@ public:
|
||||||
~Manager();
|
~Manager();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) override;
|
void doShowNativeNotification(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
MsgId msgId,
|
||||||
|
const QString &title,
|
||||||
|
const QString &subtitle,
|
||||||
|
const QString &msg,
|
||||||
|
bool hideNameAndPhoto,
|
||||||
|
bool hideReplyButton) override;
|
||||||
void doClearAllFast() override;
|
void doClearAllFast() override;
|
||||||
void doClearFromHistory(History *history) override;
|
void doClearFromHistory(History *history) override;
|
||||||
|
|
||||||
|
|
|
@ -160,7 +160,14 @@ class Manager::Private : public QObject, private base::Subscriber {
|
||||||
public:
|
public:
|
||||||
Private(Manager *manager);
|
Private(Manager *manager);
|
||||||
|
|
||||||
void showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton);
|
void showNotification(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
MsgId msgId,
|
||||||
|
const QString &title,
|
||||||
|
const QString &subtitle,
|
||||||
|
const QString &msg,
|
||||||
|
bool hideNameAndPhoto,
|
||||||
|
bool hideReplyButton);
|
||||||
void clearAll();
|
void clearAll();
|
||||||
void clearFromHistory(History *history);
|
void clearFromHistory(History *history);
|
||||||
void updateDelegate();
|
void updateDelegate();
|
||||||
|
@ -208,7 +215,14 @@ Manager::Private::Private(Manager *manager)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::Private::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
void Manager::Private::showNotification(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
MsgId msgId,
|
||||||
|
const QString &title,
|
||||||
|
const QString &subtitle,
|
||||||
|
const QString &msg,
|
||||||
|
bool hideNameAndPhoto,
|
||||||
|
bool hideReplyButton) {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
NSUserNotification *notification = [[[NSUserNotification alloc] init] autorelease];
|
NSUserNotification *notification = [[[NSUserNotification alloc] init] autorelease];
|
||||||
|
@ -329,8 +343,22 @@ Manager::Manager(Window::Notifications::System *system) : NativeManager(system)
|
||||||
|
|
||||||
Manager::~Manager() = default;
|
Manager::~Manager() = default;
|
||||||
|
|
||||||
void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
void Manager::doShowNativeNotification(
|
||||||
_private->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton);
|
not_null<PeerData*> peer,
|
||||||
|
MsgId msgId,
|
||||||
|
const QString &title,
|
||||||
|
const QString &subtitle,
|
||||||
|
const QString &msg,
|
||||||
|
bool hideNameAndPhoto,
|
||||||
|
bool hideReplyButton) {
|
||||||
|
_private->showNotification(
|
||||||
|
peer,
|
||||||
|
msgId,
|
||||||
|
title,
|
||||||
|
subtitle,
|
||||||
|
msg,
|
||||||
|
hideNameAndPhoto,
|
||||||
|
hideReplyButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::doClearAllFast() {
|
void Manager::doClearAllFast() {
|
||||||
|
|
|
@ -342,7 +342,14 @@ public:
|
||||||
explicit Private(Manager *instance, Type type);
|
explicit Private(Manager *instance, Type type);
|
||||||
bool init();
|
bool init();
|
||||||
|
|
||||||
bool showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton);
|
bool showNotification(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
MsgId msgId,
|
||||||
|
const QString &title,
|
||||||
|
const QString &subtitle,
|
||||||
|
const QString &msg,
|
||||||
|
bool hideNameAndPhoto,
|
||||||
|
bool hideReplyButton);
|
||||||
void clearAll();
|
void clearAll();
|
||||||
void clearFromHistory(History *history);
|
void clearFromHistory(History *history);
|
||||||
void beforeNotificationActivated(PeerId peerId, MsgId msgId);
|
void beforeNotificationActivated(PeerId peerId, MsgId msgId);
|
||||||
|
@ -447,13 +454,24 @@ void Manager::Private::clearNotification(PeerId peerId, MsgId msgId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Manager::Private::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
bool Manager::Private::showNotification(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
MsgId msgId,
|
||||||
|
const QString &title,
|
||||||
|
const QString &subtitle,
|
||||||
|
const QString &msg,
|
||||||
|
bool hideNameAndPhoto,
|
||||||
|
bool hideReplyButton) {
|
||||||
if (!_notificationManager || !_notifier || !_notificationFactory) return false;
|
if (!_notificationManager || !_notifier || !_notificationFactory) return false;
|
||||||
|
|
||||||
ComPtr<IXmlDocument> toastXml;
|
ComPtr<IXmlDocument> toastXml;
|
||||||
bool withSubtitle = !subtitle.isEmpty();
|
bool withSubtitle = !subtitle.isEmpty();
|
||||||
|
|
||||||
HRESULT hr = _notificationManager->GetTemplateContent(withSubtitle ? ToastTemplateType_ToastImageAndText04 : ToastTemplateType_ToastImageAndText02, &toastXml);
|
HRESULT hr = _notificationManager->GetTemplateContent(
|
||||||
|
(withSubtitle
|
||||||
|
? ToastTemplateType_ToastImageAndText04
|
||||||
|
: ToastTemplateType_ToastImageAndText02),
|
||||||
|
&toastXml);
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
|
||||||
hr = SetAudioSilent(toastXml.Get());
|
hr = SetAudioSilent(toastXml.Get());
|
||||||
|
@ -560,8 +578,22 @@ void Manager::clearNotification(PeerId peerId, MsgId msgId) {
|
||||||
|
|
||||||
Manager::~Manager() = default;
|
Manager::~Manager() = default;
|
||||||
|
|
||||||
void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
void Manager::doShowNativeNotification(
|
||||||
_private->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton);
|
not_null<PeerData*> peer,
|
||||||
|
MsgId msgId,
|
||||||
|
const QString &title,
|
||||||
|
const QString &subtitle,
|
||||||
|
const QString &msg,
|
||||||
|
bool hideNameAndPhoto,
|
||||||
|
bool hideReplyButton) {
|
||||||
|
_private->showNotification(
|
||||||
|
peer,
|
||||||
|
msgId,
|
||||||
|
title,
|
||||||
|
subtitle,
|
||||||
|
msg,
|
||||||
|
hideNameAndPhoto,
|
||||||
|
hideReplyButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::doClearAllFast() {
|
void Manager::doClearAllFast() {
|
||||||
|
|
|
@ -23,7 +23,14 @@ public:
|
||||||
~Manager();
|
~Manager();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) override;
|
void doShowNativeNotification(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
MsgId msgId,
|
||||||
|
const QString &title,
|
||||||
|
const QString &subtitle,
|
||||||
|
const QString &msg,
|
||||||
|
bool hideNameAndPhoto,
|
||||||
|
bool hideReplyButton) override;
|
||||||
void doClearAllFast() override;
|
void doClearAllFast() override;
|
||||||
void doClearFromHistory(History *history) override;
|
void doClearFromHistory(History *history) override;
|
||||||
void onBeforeNotificationActivated(PeerId peerId, MsgId msgId) override;
|
void onBeforeNotificationActivated(PeerId peerId, MsgId msgId) override;
|
||||||
|
|
|
@ -3322,7 +3322,9 @@ IsolatedEmoji String::toIsolatedEmoji() const {
|
||||||
auto index = 0;
|
auto index = 0;
|
||||||
for (const auto &block : _blocks) {
|
for (const auto &block : _blocks) {
|
||||||
const auto type = block->type();
|
const auto type = block->type();
|
||||||
if (type == TextBlockTEmoji) {
|
if (block->lnkIndex()) {
|
||||||
|
return IsolatedEmoji();
|
||||||
|
} else if (type == TextBlockTEmoji) {
|
||||||
result.items[index++] = static_cast<EmojiBlock*>(block.get())->emoji;
|
result.items[index++] = static_cast<EmojiBlock*>(block.get())->emoji;
|
||||||
} else if (type != TextBlockTSkip) {
|
} else if (type != TextBlockTSkip) {
|
||||||
return IsolatedEmoji();
|
return IsolatedEmoji();
|
||||||
|
|
|
@ -61,45 +61,58 @@ void System::createManager() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::schedule(
|
System::SkipState System::skipNotification(
|
||||||
not_null<History*> history,
|
not_null<HistoryItem*> item) const {
|
||||||
not_null<HistoryItem*> item) {
|
const auto history = item->history();
|
||||||
if (App::quitting()
|
const auto notifyBy = item->specialNotificationPeer();
|
||||||
|| !history->currentNotification()
|
if (App::quitting() || !history->currentNotification()) {
|
||||||
|| !Main::Session::Exists()) return;
|
return { SkipState::Skip };
|
||||||
|
}
|
||||||
const auto notifyBy = (!history->peer->isUser() && item->mentionsMe())
|
const auto scheduled = item->out() && item->isFromScheduled();
|
||||||
? item->from().get()
|
|
||||||
: nullptr;
|
|
||||||
|
|
||||||
history->owner().requestNotifySettings(history->peer);
|
history->owner().requestNotifySettings(history->peer);
|
||||||
if (notifyBy) {
|
if (notifyBy) {
|
||||||
history->owner().requestNotifySettings(notifyBy);
|
history->owner().requestNotifySettings(notifyBy);
|
||||||
}
|
}
|
||||||
auto haveSetting = !history->owner().notifyMuteUnknown(history->peer);
|
|
||||||
if (haveSetting && history->owner().notifyIsMuted(history->peer)) {
|
if (history->owner().notifyMuteUnknown(history->peer)) {
|
||||||
if (notifyBy) {
|
return { SkipState::Unknown, item->isSilent() };
|
||||||
haveSetting = !history->owner().notifyMuteUnknown(notifyBy);
|
} else if (!history->owner().notifyIsMuted(history->peer)) {
|
||||||
if (haveSetting) {
|
return { SkipState::DontSkip, item->isSilent() };
|
||||||
if (history->owner().notifyIsMuted(notifyBy)) {
|
} else if (!notifyBy) {
|
||||||
history->popNotification(item);
|
return {
|
||||||
return;
|
scheduled ? SkipState::DontSkip : SkipState::Skip,
|
||||||
}
|
item->isSilent() || scheduled
|
||||||
}
|
};
|
||||||
} else {
|
} else if (history->owner().notifyMuteUnknown(notifyBy)) {
|
||||||
history->popNotification(item);
|
return { SkipState::Unknown, item->isSilent() };
|
||||||
return;
|
} else if (!history->owner().notifyIsMuted(notifyBy)) {
|
||||||
}
|
return { SkipState::DontSkip, item->isSilent() };
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
scheduled ? SkipState::DontSkip : SkipState::Skip,
|
||||||
|
item->isSilent() || scheduled
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (!item->notificationReady()) {
|
}
|
||||||
haveSetting = false;
|
|
||||||
|
void System::schedule(not_null<HistoryItem*> item) {
|
||||||
|
const auto history = item->history();
|
||||||
|
const auto skip = skipNotification(item);
|
||||||
|
if (skip.value == SkipState::Skip) {
|
||||||
|
history->popNotification(item);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
const auto notifyBy = item->specialNotificationPeer();
|
||||||
|
const auto ready = (skip.value != SkipState::Unknown)
|
||||||
|
&& item->notificationReady();
|
||||||
|
|
||||||
auto delay = item->Has<HistoryMessageForwarded>() ? 500 : 100;
|
auto delay = item->Has<HistoryMessageForwarded>() ? 500 : 100;
|
||||||
auto t = base::unixtime::now();
|
const auto t = base::unixtime::now();
|
||||||
auto ms = crl::now();
|
const auto ms = crl::now();
|
||||||
bool isOnline = App::main()->lastWasOnline(), otherNotOld = ((cOtherOnline() * 1000LL) + Global::OnlineCloudTimeout() > t * 1000LL);
|
const bool isOnline = App::main()->lastWasOnline();
|
||||||
bool otherLaterThanMe = (cOtherOnline() * 1000LL + (ms - App::main()->lastSetOnline()) > t * 1000LL);
|
const auto otherNotOld = ((cOtherOnline() * 1000LL) + Global::OnlineCloudTimeout() > t * 1000LL);
|
||||||
|
const bool otherLaterThanMe = (cOtherOnline() * 1000LL + (ms - App::main()->lastSetOnline()) > t * 1000LL);
|
||||||
if (!isOnline && otherNotOld && otherLaterThanMe) {
|
if (!isOnline && otherNotOld && otherLaterThanMe) {
|
||||||
delay = Global::NotifyCloudDelay();
|
delay = Global::NotifyCloudDelay();
|
||||||
} else if (cOtherOnline() >= t) {
|
} else if (cOtherOnline() >= t) {
|
||||||
|
@ -107,7 +120,7 @@ void System::schedule(
|
||||||
}
|
}
|
||||||
|
|
||||||
auto when = ms + delay;
|
auto when = ms + delay;
|
||||||
if (!item->isSilent()) {
|
if (!skip.silent) {
|
||||||
_whenAlerts[history].insert(when, notifyBy);
|
_whenAlerts[history].insert(when, notifyBy);
|
||||||
}
|
}
|
||||||
if (Global::DesktopNotify() && !Platform::Notifications::SkipToast()) {
|
if (Global::DesktopNotify() && !Platform::Notifications::SkipToast()) {
|
||||||
|
@ -116,13 +129,13 @@ void System::schedule(
|
||||||
whenMap.insert(item->id, when);
|
whenMap.insert(item->id, when);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &addTo = haveSetting ? _waiters : _settingWaiters;
|
auto &addTo = ready ? _waiters : _settingWaiters;
|
||||||
auto it = addTo.constFind(history);
|
const auto it = addTo.constFind(history);
|
||||||
if (it == addTo.cend() || it->when > when) {
|
if (it == addTo.cend() || it->when > when) {
|
||||||
addTo.insert(history, Waiter(item->id, when, notifyBy));
|
addTo.insert(history, Waiter(item->id, when, notifyBy));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (haveSetting) {
|
if (ready) {
|
||||||
if (!_waitTimer.isActive() || _waitTimer.remainingTime() > delay) {
|
if (!_waitTimer.isActive() || _waitTimer.remainingTime() > delay) {
|
||||||
_waitTimer.callOnce(delay);
|
_waitTimer.callOnce(delay);
|
||||||
}
|
}
|
||||||
|
@ -524,9 +537,12 @@ void Manager::notificationReplied(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeManager::doShowNotification(HistoryItem *item, int forwardedCount) {
|
void NativeManager::doShowNotification(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
int forwardedCount) {
|
||||||
const auto options = getNotificationOptions(item);
|
const auto options = getNotificationOptions(item);
|
||||||
|
|
||||||
|
const auto scheduled = (item->out() && item->isFromScheduled());
|
||||||
const auto title = options.hideNameAndPhoto ? qsl("Telegram Desktop") : item->history()->peer->name;
|
const auto title = options.hideNameAndPhoto ? qsl("Telegram Desktop") : item->history()->peer->name;
|
||||||
const auto subtitle = options.hideNameAndPhoto ? QString() : item->notificationHeader();
|
const auto subtitle = options.hideNameAndPhoto ? QString() : item->notificationHeader();
|
||||||
const auto text = options.hideMessageText
|
const auto text = options.hideMessageText
|
||||||
|
@ -539,7 +555,7 @@ void NativeManager::doShowNotification(HistoryItem *item, int forwardedCount) {
|
||||||
item->history()->peer,
|
item->history()->peer,
|
||||||
item->id,
|
item->id,
|
||||||
title,
|
title,
|
||||||
subtitle,
|
scheduled ? WrapFromScheduled(subtitle) : subtitle,
|
||||||
text,
|
text,
|
||||||
options.hideNameAndPhoto,
|
options.hideNameAndPhoto,
|
||||||
options.hideReplyButton);
|
options.hideReplyButton);
|
||||||
|
@ -547,5 +563,9 @@ void NativeManager::doShowNotification(HistoryItem *item, int forwardedCount) {
|
||||||
|
|
||||||
System::~System() = default;
|
System::~System() = default;
|
||||||
|
|
||||||
|
QString WrapFromScheduled(const QString &text) {
|
||||||
|
return QString::fromUtf8("\xF0\x9F\x93\x85 ") + text;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Notifications
|
} // namespace Notifications
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
|
@ -62,7 +62,7 @@ public:
|
||||||
void createManager();
|
void createManager();
|
||||||
|
|
||||||
void checkDelayed();
|
void checkDelayed();
|
||||||
void schedule(not_null<History*> history, not_null<HistoryItem*> item);
|
void schedule(not_null<HistoryItem*> item);
|
||||||
void clearFromHistory(History *history);
|
void clearFromHistory(History *history);
|
||||||
void clearFromItem(HistoryItem *item);
|
void clearFromItem(HistoryItem *item);
|
||||||
void clearAll();
|
void clearAll();
|
||||||
|
@ -80,6 +80,18 @@ public:
|
||||||
~System();
|
~System();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct SkipState {
|
||||||
|
enum Value {
|
||||||
|
Unknown,
|
||||||
|
Skip,
|
||||||
|
DontSkip
|
||||||
|
};
|
||||||
|
Value value = Value::Unknown;
|
||||||
|
bool silent = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
SkipState skipNotification(not_null<HistoryItem*> item) const;
|
||||||
|
|
||||||
void showNext();
|
void showNext();
|
||||||
void showGrouped();
|
void showGrouped();
|
||||||
void ensureSoundCreated();
|
void ensureSoundCreated();
|
||||||
|
@ -122,7 +134,9 @@ public:
|
||||||
explicit Manager(not_null<System*> system) : _system(system) {
|
explicit Manager(not_null<System*> system) : _system(system) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void showNotification(HistoryItem *item, int forwardedCount) {
|
void showNotification(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
int forwardedCount) {
|
||||||
doShowNotification(item, forwardedCount);
|
doShowNotification(item, forwardedCount);
|
||||||
}
|
}
|
||||||
void updateAll() {
|
void updateAll() {
|
||||||
|
@ -162,7 +176,9 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void doUpdateAll() = 0;
|
virtual void doUpdateAll() = 0;
|
||||||
virtual void doShowNotification(HistoryItem *item, int forwardedCount) = 0;
|
virtual void doShowNotification(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
int forwardedCount) = 0;
|
||||||
virtual void doClearAll() = 0;
|
virtual void doClearAll() = 0;
|
||||||
virtual void doClearAllFast() = 0;
|
virtual void doClearAllFast() = 0;
|
||||||
virtual void doClearFromItem(HistoryItem *item) = 0;
|
virtual void doClearFromItem(HistoryItem *item) = 0;
|
||||||
|
@ -193,11 +209,22 @@ protected:
|
||||||
}
|
}
|
||||||
void doClearFromItem(HistoryItem *item) override {
|
void doClearFromItem(HistoryItem *item) override {
|
||||||
}
|
}
|
||||||
void doShowNotification(HistoryItem *item, int forwardedCount) override;
|
void doShowNotification(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
int forwardedCount) override;
|
||||||
|
|
||||||
virtual void doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) = 0;
|
virtual void doShowNativeNotification(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
MsgId msgId,
|
||||||
|
const QString &title,
|
||||||
|
const QString &subtitle,
|
||||||
|
const QString &msg,
|
||||||
|
bool hideNameAndPhoto,
|
||||||
|
bool hideReplyButton) = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QString WrapFromScheduled(const QString &text);
|
||||||
|
|
||||||
} // namespace Notifications
|
} // namespace Notifications
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
|
#include "ui/text_options.h"
|
||||||
#include "dialogs/dialogs_layout.h"
|
#include "dialogs/dialogs_layout.h"
|
||||||
#include "window/themes/window_theme.h"
|
#include "window/themes/window_theme.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
|
@ -66,13 +67,14 @@ Manager::Manager(System *system)
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager::QueuedNotification::QueuedNotification(
|
Manager::QueuedNotification::QueuedNotification(
|
||||||
not_null<HistoryItem*> item
|
not_null<HistoryItem*> item,
|
||||||
, int forwardedCount)
|
int forwardedCount)
|
||||||
: history(item->history())
|
: history(item->history())
|
||||||
, peer(history->peer)
|
, peer(history->peer)
|
||||||
, author((!peer->isUser() && !item->isPost()) ? item->author().get() : nullptr)
|
, author(item->notificationHeader())
|
||||||
, item((forwardedCount < 2) ? item.get() : nullptr)
|
, item((forwardedCount < 2) ? item.get() : nullptr)
|
||||||
, forwardedCount(forwardedCount) {
|
, forwardedCount(forwardedCount)
|
||||||
|
, fromScheduled(item->out() && item->isFromScheduled()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap Manager::hiddenUserpicPlaceholder() const {
|
QPixmap Manager::hiddenUserpicPlaceholder() const {
|
||||||
|
@ -206,7 +208,10 @@ void Manager::showNextFromQueue() {
|
||||||
queued.author,
|
queued.author,
|
||||||
queued.item,
|
queued.item,
|
||||||
queued.forwardedCount,
|
queued.forwardedCount,
|
||||||
startPosition, startShift, shiftDirection);
|
queued.fromScheduled,
|
||||||
|
startPosition,
|
||||||
|
startShift,
|
||||||
|
shiftDirection);
|
||||||
_notifications.push_back(std::move(notification));
|
_notifications.push_back(std::move(notification));
|
||||||
--count;
|
--count;
|
||||||
} while (count > 0 && !_queuedNotifications.empty());
|
} while (count > 0 && !_queuedNotifications.empty());
|
||||||
|
@ -289,7 +294,9 @@ void Manager::removeWidget(internal::Widget *remove) {
|
||||||
showNextFromQueue();
|
showNextFromQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::doShowNotification(HistoryItem *item, int forwardedCount) {
|
void Manager::doShowNotification(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
int forwardedCount) {
|
||||||
_queuedNotifications.emplace_back(item, forwardedCount);
|
_queuedNotifications.emplace_back(item, forwardedCount);
|
||||||
showNextFromQueue();
|
showNextFromQueue();
|
||||||
}
|
}
|
||||||
|
@ -353,7 +360,12 @@ Manager::~Manager() {
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
Widget::Widget(Manager *manager, QPoint startPosition, int shift, Direction shiftDirection) : TWidget(nullptr)
|
Widget::Widget(
|
||||||
|
not_null<Manager*> manager,
|
||||||
|
QPoint startPosition,
|
||||||
|
int shift,
|
||||||
|
Direction shiftDirection)
|
||||||
|
: TWidget(nullptr)
|
||||||
, _manager(manager)
|
, _manager(manager)
|
||||||
, _startPosition(startPosition)
|
, _startPosition(startPosition)
|
||||||
, _direction(shiftDirection)
|
, _direction(shiftDirection)
|
||||||
|
@ -501,12 +513,13 @@ void Background::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Notification::Notification(
|
Notification::Notification(
|
||||||
Manager *manager,
|
not_null<Manager*> manager,
|
||||||
History *history,
|
not_null<History*> history,
|
||||||
PeerData *peer,
|
not_null<PeerData*> peer,
|
||||||
PeerData *author,
|
const QString &author,
|
||||||
HistoryItem *msg,
|
HistoryItem *item,
|
||||||
int forwardedCount,
|
int forwardedCount,
|
||||||
|
bool fromScheduled,
|
||||||
QPoint startPosition,
|
QPoint startPosition,
|
||||||
int shift,
|
int shift,
|
||||||
Direction shiftDirection)
|
Direction shiftDirection)
|
||||||
|
@ -515,8 +528,9 @@ Notification::Notification(
|
||||||
, _history(history)
|
, _history(history)
|
||||||
, _peer(peer)
|
, _peer(peer)
|
||||||
, _author(author)
|
, _author(author)
|
||||||
, _item(msg)
|
, _item(item)
|
||||||
, _forwardedCount(forwardedCount)
|
, _forwardedCount(forwardedCount)
|
||||||
|
, _fromScheduled(fromScheduled)
|
||||||
, _close(this, st::notifyClose)
|
, _close(this, st::notifyClose)
|
||||||
, _reply(this, tr::lng_notification_reply(), st::defaultBoxButton) {
|
, _reply(this, tr::lng_notification_reply(), st::defaultBoxButton) {
|
||||||
subscribe(Lang::Current().updated(), [this] { refreshLang(); });
|
subscribe(Lang::Current().updated(), [this] { refreshLang(); });
|
||||||
|
@ -683,35 +697,53 @@ void Notification::updateNotifyDisplay() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.hideMessageText) {
|
if (!options.hideMessageText) {
|
||||||
const HistoryItem *textCachedFor = nullptr;
|
auto itemTextCache = Ui::Text::String(itemWidth);
|
||||||
Ui::Text::String itemTextCache(itemWidth);
|
auto r = QRect(
|
||||||
QRect r(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height, itemWidth, 2 * st::dialogsTextFont->height);
|
st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft,
|
||||||
if (_item) {
|
st::notifyItemTop + st::msgNameFont->height,
|
||||||
auto active = false, selected = false;
|
itemWidth,
|
||||||
_item->drawInDialog(
|
2 * st::dialogsTextFont->height);
|
||||||
p,
|
p.setTextPalette(st::dialogsTextPalette);
|
||||||
r,
|
p.setPen(st::dialogsTextFg);
|
||||||
active,
|
p.setFont(st::dialogsTextFont);
|
||||||
selected,
|
const auto text = _item
|
||||||
HistoryItem::DrawInDialog::Normal,
|
? _item->inDialogsText(HistoryItem::DrawInDialog::Normal)
|
||||||
textCachedFor,
|
: ((!_author.isEmpty()
|
||||||
itemTextCache);
|
? textcmdLink(1, _author)
|
||||||
} else if (_forwardedCount > 1) {
|
: QString())
|
||||||
p.setFont(st::dialogsTextFont);
|
+ (_forwardedCount > 1
|
||||||
if (_author) {
|
? ('\n' + tr::lng_forward_messages(
|
||||||
itemTextCache.setText(st::dialogsTextStyle, _author->name);
|
tr::now,
|
||||||
p.setPen(st::dialogsTextFgService);
|
lt_count,
|
||||||
itemTextCache.drawElided(p, r.left(), r.top(), r.width());
|
_forwardedCount))
|
||||||
r.setTop(r.top() + st::dialogsTextFont->height);
|
: QString()));
|
||||||
}
|
const auto Options = TextParseOptions{
|
||||||
p.setPen(st::dialogsTextFg);
|
TextParseRichText
|
||||||
p.drawText(r.left(), r.top() + st::dialogsTextFont->ascent, tr::lng_forward_messages(tr::now, lt_count, _forwardedCount));
|
| (_forwardedCount > 1 ? TextParseMultiline : 0),
|
||||||
}
|
0,
|
||||||
|
0,
|
||||||
|
Qt::LayoutDirectionAuto,
|
||||||
|
};
|
||||||
|
itemTextCache.setText(
|
||||||
|
st::dialogsTextStyle,
|
||||||
|
_fromScheduled ? WrapFromScheduled(text) : text,
|
||||||
|
Options);
|
||||||
|
itemTextCache.drawElided(
|
||||||
|
p,
|
||||||
|
r.left(),
|
||||||
|
r.top(),
|
||||||
|
r.width(),
|
||||||
|
r.height() / st::dialogsTextFont->height);
|
||||||
|
p.restoreTextPalette();
|
||||||
} else {
|
} else {
|
||||||
static QString notifyText = st::dialogsTextFont->elided(tr::lng_notification_preview(tr::now), itemWidth);
|
|
||||||
p.setFont(st::dialogsTextFont);
|
p.setFont(st::dialogsTextFont);
|
||||||
p.setPen(st::dialogsTextFgService);
|
p.setPen(st::dialogsTextFgService);
|
||||||
p.drawText(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height + st::dialogsTextFont->ascent, notifyText);
|
p.drawText(
|
||||||
|
st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft,
|
||||||
|
st::notifyItemTop + st::msgNameFont->height + st::dialogsTextFont->ascent,
|
||||||
|
st::dialogsTextFont->elided(
|
||||||
|
tr::lng_notification_preview(tr::now),
|
||||||
|
itemWidth));
|
||||||
}
|
}
|
||||||
|
|
||||||
p.setPen(st::dialogsNameFg);
|
p.setPen(st::dialogsNameFg);
|
||||||
|
@ -839,7 +871,7 @@ void Notification::changeHeight(int newHeight) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Notification::unlinkHistory(History *history) {
|
bool Notification::unlinkHistory(History *history) {
|
||||||
auto unlink = _history && (history == _history || !history);
|
const auto unlink = _history && (history == _history || !history);
|
||||||
if (unlink) {
|
if (unlink) {
|
||||||
hideFast();
|
hideFast();
|
||||||
_history = nullptr;
|
_history = nullptr;
|
||||||
|
@ -897,7 +929,12 @@ void Notification::stopHiding() {
|
||||||
Widget::hideStop();
|
Widget::hideStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
HideAllButton::HideAllButton(Manager *manager, QPoint startPosition, int shift, Direction shiftDirection) : Widget(manager, startPosition, shift, shiftDirection) {
|
HideAllButton::HideAllButton(
|
||||||
|
not_null<Manager*> manager,
|
||||||
|
QPoint startPosition,
|
||||||
|
int shift,
|
||||||
|
Direction shiftDirection)
|
||||||
|
: Widget(manager, startPosition, shift, shiftDirection) {
|
||||||
setCursor(style::cur_pointer);
|
setCursor(style::cur_pointer);
|
||||||
|
|
||||||
auto position = computePosition(st::notifyHideAllHeight);
|
auto position = computePosition(st::notifyHideAllHeight);
|
||||||
|
|
|
@ -52,7 +52,9 @@ private:
|
||||||
QPixmap hiddenUserpicPlaceholder() const;
|
QPixmap hiddenUserpicPlaceholder() const;
|
||||||
|
|
||||||
void doUpdateAll() override;
|
void doUpdateAll() override;
|
||||||
void doShowNotification(HistoryItem *item, int forwardedCount) override;
|
void doShowNotification(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
int forwardedCount) override;
|
||||||
void doClearAll() override;
|
void doClearAll() override;
|
||||||
void doClearAllFast() override;
|
void doClearAllFast() override;
|
||||||
void doClearFromHistory(History *history) override;
|
void doClearFromHistory(History *history) override;
|
||||||
|
@ -87,9 +89,10 @@ private:
|
||||||
|
|
||||||
not_null<History*> history;
|
not_null<History*> history;
|
||||||
not_null<PeerData*> peer;
|
not_null<PeerData*> peer;
|
||||||
PeerData *author;
|
QString author;
|
||||||
HistoryItem *item;
|
HistoryItem *item = nullptr;
|
||||||
int forwardedCount;
|
int forwardedCount = 0;
|
||||||
|
bool fromScheduled = false;
|
||||||
};
|
};
|
||||||
std::deque<QueuedNotification> _queuedNotifications;
|
std::deque<QueuedNotification> _queuedNotifications;
|
||||||
|
|
||||||
|
@ -107,7 +110,11 @@ public:
|
||||||
Up,
|
Up,
|
||||||
Down,
|
Down,
|
||||||
};
|
};
|
||||||
Widget(Manager *manager, QPoint startPosition, int shift, Direction shiftDirection);
|
Widget(
|
||||||
|
not_null<Manager*> manager,
|
||||||
|
QPoint startPosition,
|
||||||
|
int shift,
|
||||||
|
Direction shiftDirection);
|
||||||
|
|
||||||
bool isShowing() const {
|
bool isShowing() const {
|
||||||
return _a_opacity.animating() && !_hiding;
|
return _a_opacity.animating() && !_hiding;
|
||||||
|
@ -131,7 +138,7 @@ protected:
|
||||||
virtual void updateGeometry(int x, int y, int width, int height);
|
virtual void updateGeometry(int x, int y, int width, int height);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Manager *manager() const {
|
not_null<Manager*> manager() const {
|
||||||
return _manager;
|
return _manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +149,7 @@ private:
|
||||||
void hideAnimated(float64 duration, const anim::transition &func);
|
void hideAnimated(float64 duration, const anim::transition &func);
|
||||||
bool shiftAnimationCallback(crl::time now);
|
bool shiftAnimationCallback(crl::time now);
|
||||||
|
|
||||||
Manager *_manager = nullptr;
|
const not_null<Manager*> _manager;
|
||||||
|
|
||||||
bool _hiding = false;
|
bool _hiding = false;
|
||||||
bool _deleted = false;
|
bool _deleted = false;
|
||||||
|
@ -168,12 +175,13 @@ protected:
|
||||||
class Notification : public Widget {
|
class Notification : public Widget {
|
||||||
public:
|
public:
|
||||||
Notification(
|
Notification(
|
||||||
Manager *manager,
|
not_null<Manager*> manager,
|
||||||
History *history,
|
not_null<History*> history,
|
||||||
PeerData *peer,
|
not_null<PeerData*> peer,
|
||||||
PeerData *author,
|
const QString &author,
|
||||||
HistoryItem *item,
|
HistoryItem *item,
|
||||||
int forwardedCount,
|
int forwardedCount,
|
||||||
|
bool fromScheduled,
|
||||||
QPoint startPosition,
|
QPoint startPosition,
|
||||||
int shift,
|
int shift,
|
||||||
Direction shiftDirection);
|
Direction shiftDirection);
|
||||||
|
@ -228,11 +236,12 @@ private:
|
||||||
|
|
||||||
crl::time _started;
|
crl::time _started;
|
||||||
|
|
||||||
History *_history;
|
History *_history = nullptr;
|
||||||
PeerData *_peer;
|
PeerData *_peer = nullptr;
|
||||||
PeerData *_author;
|
QString _author;
|
||||||
HistoryItem *_item;
|
HistoryItem *_item = nullptr;
|
||||||
int _forwardedCount;
|
int _forwardedCount = 0;
|
||||||
|
bool _fromScheduled = false;
|
||||||
object_ptr<Ui::IconButton> _close;
|
object_ptr<Ui::IconButton> _close;
|
||||||
object_ptr<Ui::RoundButton> _reply;
|
object_ptr<Ui::RoundButton> _reply;
|
||||||
object_ptr<Background> _background = { nullptr };
|
object_ptr<Background> _background = { nullptr };
|
||||||
|
@ -250,7 +259,11 @@ private:
|
||||||
|
|
||||||
class HideAllButton : public Widget {
|
class HideAllButton : public Widget {
|
||||||
public:
|
public:
|
||||||
HideAllButton(Manager *manager, QPoint startPosition, int shift, Direction shiftDirection);
|
HideAllButton(
|
||||||
|
not_null<Manager*> manager,
|
||||||
|
QPoint startPosition,
|
||||||
|
int shift,
|
||||||
|
Direction shiftDirection);
|
||||||
|
|
||||||
void startHiding();
|
void startHiding();
|
||||||
void startHidingFast();
|
void startHidingFast();
|
||||||
|
|
Loading…
Add table
Reference in a new issue