From 07f45b7eab88dd6d498b233f3708b0750d292e29 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Wed, 28 Aug 2019 21:20:49 +0300
Subject: [PATCH] Improve published scheduled notifications.

---
 Telegram/Resources/langs/lang.strings         |   1 +
 Telegram/SourceFiles/data/data_session.cpp    |   4 +-
 Telegram/SourceFiles/data/data_session.h      |   4 +
 Telegram/SourceFiles/history/history.cpp      |   7 +-
 Telegram/SourceFiles/history/history.h        |   2 -
 Telegram/SourceFiles/history/history_item.cpp |   2 +-
 .../SourceFiles/history/history_message.cpp   |   2 +-
 .../SourceFiles/history/history_widget.cpp    |  13 +-
 .../platform/mac/notifications_manager_mac.mm |   5 +-
 Telegram/SourceFiles/ui/empty_userpic.cpp     | 214 ++++++++++++------
 Telegram/SourceFiles/ui/empty_userpic.h       |  16 ++
 .../window/notifications_manager.cpp          |  25 +-
 .../window/notifications_manager_default.cpp  |  38 +++-
 .../window/notifications_utilities.cpp        |   8 +-
 14 files changed, 239 insertions(+), 102 deletions(-)

diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index 56decef54..ece3d18e0 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -297,6 +297,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 "lng_notification_reply" = "Reply";
 "lng_notification_hide_all" = "Hide all";
 "lng_notification_sample" = "This is a sample notification";
+"lng_notification_reminder" = "Reminder";
 
 "lng_settings_section_general" = "General";
 "lng_settings_change_lang" = "Change language";
diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp
index 7626ab991..cb081870b 100644
--- a/Telegram/SourceFiles/data/data_session.cpp
+++ b/Telegram/SourceFiles/data/data_session.cpp
@@ -1202,7 +1202,9 @@ void Session::changeMessageId(ChannelId channel, MsgId wasId, MsgId nowId) {
 	Assert(i != list->end());
 	auto owned = std::move(i->second);
 	list->erase(i);
-	list->emplace(nowId, std::move(owned));
+	const auto [j, ok] = list->emplace(nowId, std::move(owned));
+
+	Ensures(ok);
 }
 
 void Session::notifyItemIdChange(IdChange event) {
diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h
index 17e6eb8a1..9a8379579 100644
--- a/Telegram/SourceFiles/data/data_session.h
+++ b/Telegram/SourceFiles/data/data_session.h
@@ -91,6 +91,9 @@ public:
 	[[nodiscard]] ScheduledMessages &scheduledMessages() const {
 		return *_scheduledMessages;
 	}
+	[[nodiscard]] MsgId nextNonHistoryEntryId() {
+		return ++_nonHistoryEntryId;
+	}
 
 	void clear();
 
@@ -991,6 +994,7 @@ private:
 
 	Groups _groups;
 	std::unique_ptr<ScheduledMessages> _scheduledMessages;
+	MsgId _nonHistoryEntryId = ServerMaxMsgId;
 
 	rpl::lifetime _lifetime;
 
diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp
index f00ef46a8..3106c226c 100644
--- a/Telegram/SourceFiles/history/history.cpp
+++ b/Telegram/SourceFiles/history/history.cpp
@@ -1658,7 +1658,10 @@ void History::inboxRead(MsgId upTo, std::optional<int> stillUnread) {
 	}
 
 	_firstUnreadView = nullptr;
-	session().notifications().clearFromHistory(this);
+	if (!peer->isSelf()) {
+		// Only reminders generate notifications in Saved Messages.
+		session().notifications().clearFromHistory(this);
+	}
 }
 
 void History::inboxRead(not_null<const HistoryItem*> wasRead) {
@@ -1832,7 +1835,7 @@ void History::getNextFirstUnreadMessage() {
 }
 
 MsgId History::nextNonHistoryEntryId() {
-	return ++_nonHistoryEntryId;
+	return owner().nextNonHistoryEntryId();
 }
 
 bool History::folderKnown() const {
diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h
index 48db8369e..b97378b0e 100644
--- a/Telegram/SourceFiles/history/history.h
+++ b/Telegram/SourceFiles/history/history.h
@@ -532,8 +532,6 @@ private:
 
 	std::deque<not_null<HistoryItem*>> _notifications;
 
-	MsgId _nonHistoryEntryId = ServerMaxMsgId;
-
  };
 
 class HistoryBlock {
diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp
index 2c17f3bfc..898cf6394 100644
--- a/Telegram/SourceFiles/history/history_item.cpp
+++ b/Telegram/SourceFiles/history/history_item.cpp
@@ -763,7 +763,7 @@ bool HistoryItem::showNotification() const {
 	if (channel && !channel->amIn()) {
 		return false;
 	}
-	return out() ? isFromScheduled() : unread();
+	return (out() || _history->peer->isSelf()) ? isFromScheduled() : unread();
 }
 
 void HistoryItem::markClientSideAsRead() {
diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp
index 7c37ce8e7..a67ea6bec 100644
--- a/Telegram/SourceFiles/history/history_message.cpp
+++ b/Telegram/SourceFiles/history/history_message.cpp
@@ -1302,7 +1302,7 @@ void HistoryMessage::dependencyItemRemoved(HistoryItem *dependency) {
 }
 
 QString HistoryMessage::notificationHeader() const {
-	if (out() && isFromScheduled()) {
+	if (out() && isFromScheduled() && !_history->peer->isSelf()) {
 		return tr::lng_from_you(tr::now);
 	} else if (!_history->peer->isUser() && !isPost()) {
 		return App::peerName(from());
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index 0de17bf5d..29c101e7d 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -2256,6 +2256,9 @@ void HistoryWidget::unreadMessageAdded(not_null<HistoryItem*> item) {
 		session().api().markMediaRead(item);
 	}
 	session().api().readServerHistoryForce(_history);
+
+	// Also clear possible scheduled messages notifications.
+	session().notifications().clearFromHistory(_history);
 }
 
 void HistoryWidget::historyToDown(History *history) {
@@ -2688,19 +2691,23 @@ bool HistoryWidget::isItemCompletelyHidden(HistoryItem *item) const {
 
 void HistoryWidget::visibleAreaUpdated() {
 	if (_list && !_scroll->isHidden()) {
-		auto scrollTop = _scroll->scrollTop();
-		auto scrollBottom = scrollTop + _scroll->height();
+		const auto scrollTop = _scroll->scrollTop();
+		const auto scrollBottom = scrollTop + _scroll->height();
 		_list->visibleAreaUpdated(scrollTop, scrollBottom);
+		const auto atBottom = (scrollTop >= _scroll->scrollTopMax());
 		if (_history->loadedAtBottom() && (_history->unreadCount() > 0 || (_migrated && _migrated->unreadCount() > 0))) {
 			const auto unread = firstUnreadMessage();
 			const auto unreadVisible = unread
 				&& (scrollBottom > _list->itemTop(unread));
-			const auto atBottom = (scrollTop >= _scroll->scrollTopMax());
 			if ((unreadVisible || atBottom)
 				 && App::wnd()->doWeReadServerHistory()) {
 				session().api().readServerHistory(_history);
 			}
 		}
+		if (_history->loadedAtBottom() && atBottom) {
+			// Clear possible scheduled messages notifications.
+			session().notifications().clearFromHistory(_history);
+		}
 		controller()->floatPlayerAreaUpdated().notify(true);
 	}
 }
diff --git a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm
index dc88b7c8c..7482b0afd 100644
--- a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm
+++ b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "platform/platform_info.h"
 #include "platform/mac/mac_utilities.h"
 #include "history/history.h"
+#include "ui/empty_userpic.h"
 #include "mainwindow.h"
 #include "styles/style_window.h"
 
@@ -237,7 +238,9 @@ void Manager::Private::showNotification(
 	[notification setSubtitle:Q2NSString(subtitle)];
 	[notification setInformativeText:Q2NSString(msg)];
 	if (!hideNameAndPhoto && [notification respondsToSelector:@selector(setContentImage:)]) {
-		auto userpic = peer->genUserpic(st::notifyMacPhotoSize);
+		auto userpic = peer->isSelf()
+			? Ui::EmptyUserpic::GenerateSavedMessages(st::notifyMacPhotoSize)
+			: peer->genUserpic(st::notifyMacPhotoSize);
 		NSImage *img = [qt_mac_create_nsimage(userpic) autorelease];
 		[notification setContentImage:img];
 	}
diff --git a/Telegram/SourceFiles/ui/empty_userpic.cpp b/Telegram/SourceFiles/ui/empty_userpic.cpp
index fdef72b68..5acd0c9df 100644
--- a/Telegram/SourceFiles/ui/empty_userpic.cpp
+++ b/Telegram/SourceFiles/ui/empty_userpic.cpp
@@ -12,86 +12,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "styles/style_history.h"
 
 namespace Ui {
+namespace {
 
-EmptyUserpic::EmptyUserpic(const style::color &color, const QString &name)
-: _color(color) {
-	fillString(name);
-}
-
-template <typename Callback>
-void EmptyUserpic::paint(
+void PaintSavedMessagesInner(
 		Painter &p,
 		int x,
 		int y,
-		int outerWidth,
-		int size,
-		Callback paintBackground) const {
-	x = rtl() ? (outerWidth - x - size) : x;
-
-	const auto fontsize = (size * 13) / 33;
-	auto font = st::historyPeerUserpicFont->f;
-	font.setPixelSize(fontsize);
-
-	PainterHighQualityEnabler hq(p);
-	p.setBrush(_color);
-	p.setPen(Qt::NoPen);
-	paintBackground();
-
-	p.setFont(font);
-	p.setBrush(Qt::NoBrush);
-	p.setPen(st::historyPeerUserpicFg);
-	p.drawText(QRect(x, y, size, size), _string, QTextOption(style::al_center));
-}
-
-void EmptyUserpic::paint(
-		Painter &p,
-		int x,
-		int y,
-		int outerWidth,
-		int size) const {
-	paint(p, x, y, outerWidth, size, [&p, x, y, size] {
-		p.drawEllipse(x, y, size, size);
-	});
-}
-
-void EmptyUserpic::paintRounded(Painter &p, int x, int y, int outerWidth, int size) const {
-	paint(p, x, y, outerWidth, size, [&p, x, y, size] {
-		p.drawRoundedRect(x, y, size, size, st::buttonRadius, st::buttonRadius);
-	});
-}
-
-void EmptyUserpic::paintSquare(Painter &p, int x, int y, int outerWidth, int size) const {
-	paint(p, x, y, outerWidth, size, [&p, x, y, size] {
-		p.fillRect(x, y, size, size, p.brush());
-	});
-}
-
-void EmptyUserpic::PaintSavedMessages(
-		Painter &p,
-		int x,
-		int y,
-		int outerWidth,
-		int size) {
-	const auto &bg = st::historyPeerSavedMessagesBg;
-	const auto &fg = st::historyPeerUserpicFg;
-	PaintSavedMessages(p, x, y, outerWidth, size, bg, fg);
-}
-
-void EmptyUserpic::PaintSavedMessages(
-		Painter &p,
-		int x,
-		int y,
-		int outerWidth,
 		int size,
 		const style::color &bg,
 		const style::color &fg) {
-	x = rtl() ? (outerWidth - x - size) : x;
-
-	PainterHighQualityEnabler hq(p);
-	p.setBrush(bg);
-	p.setPen(Qt::NoPen);
-	p.drawEllipse(x, y, size, size);
-
 	// |<----width----->|
 	//
 	// XXXXXXXXXXXXXXXXXX  ---
@@ -160,6 +89,145 @@ void EmptyUserpic::PaintSavedMessages(
 	}
 }
 
+template <typename Callback>
+[[nodiscard]] QPixmap Generate(int size, Callback callback) {
+	auto result = QImage(
+		QSize(size, size) * cIntRetinaFactor(),
+		QImage::Format_ARGB32_Premultiplied);
+	result.setDevicePixelRatio(cRetinaFactor());
+	result.fill(Qt::transparent);
+	{
+		Painter p(&result);
+		callback(p);
+	}
+	return App::pixmapFromImageInPlace(std::move(result));
+}
+
+} // namespace
+
+EmptyUserpic::EmptyUserpic(const style::color &color, const QString &name)
+: _color(color) {
+	fillString(name);
+}
+
+template <typename Callback>
+void EmptyUserpic::paint(
+		Painter &p,
+		int x,
+		int y,
+		int outerWidth,
+		int size,
+		Callback paintBackground) const {
+	x = rtl() ? (outerWidth - x - size) : x;
+
+	const auto fontsize = (size * 13) / 33;
+	auto font = st::historyPeerUserpicFont->f;
+	font.setPixelSize(fontsize);
+
+	PainterHighQualityEnabler hq(p);
+	p.setBrush(_color);
+	p.setPen(Qt::NoPen);
+	paintBackground();
+
+	p.setFont(font);
+	p.setBrush(Qt::NoBrush);
+	p.setPen(st::historyPeerUserpicFg);
+	p.drawText(QRect(x, y, size, size), _string, QTextOption(style::al_center));
+}
+
+void EmptyUserpic::paint(
+		Painter &p,
+		int x,
+		int y,
+		int outerWidth,
+		int size) const {
+	paint(p, x, y, outerWidth, size, [&p, x, y, size] {
+		p.drawEllipse(x, y, size, size);
+	});
+}
+
+void EmptyUserpic::paintRounded(Painter &p, int x, int y, int outerWidth, int size) const {
+	paint(p, x, y, outerWidth, size, [&p, x, y, size] {
+		p.drawRoundedRect(x, y, size, size, st::buttonRadius, st::buttonRadius);
+	});
+}
+
+void EmptyUserpic::paintSquare(Painter &p, int x, int y, int outerWidth, int size) const {
+	paint(p, x, y, outerWidth, size, [&p, x, y, size] {
+		p.fillRect(x, y, size, size, p.brush());
+	});
+}
+
+void EmptyUserpic::PaintSavedMessages(
+		Painter &p,
+		int x,
+		int y,
+		int outerWidth,
+		int size) {
+	const auto &bg = st::historyPeerSavedMessagesBg;
+	const auto &fg = st::historyPeerUserpicFg;
+	PaintSavedMessages(p, x, y, outerWidth, size, bg, fg);
+}
+
+void EmptyUserpic::PaintSavedMessagesRounded(
+		Painter &p,
+		int x,
+		int y,
+		int outerWidth,
+		int size) {
+	const auto &bg = st::historyPeerSavedMessagesBg;
+	const auto &fg = st::historyPeerUserpicFg;
+	PaintSavedMessagesRounded(p, x, y, outerWidth, size, bg, fg);
+}
+
+void EmptyUserpic::PaintSavedMessages(
+		Painter &p,
+		int x,
+		int y,
+		int outerWidth,
+		int size,
+		const style::color &bg,
+		const style::color &fg) {
+	x = rtl() ? (outerWidth - x - size) : x;
+
+	PainterHighQualityEnabler hq(p);
+	p.setBrush(bg);
+	p.setPen(Qt::NoPen);
+	p.drawEllipse(x, y, size, size);
+
+	PaintSavedMessagesInner(p, x, y, size, bg, fg);
+}
+
+void EmptyUserpic::PaintSavedMessagesRounded(
+		Painter &p,
+		int x,
+		int y,
+		int outerWidth,
+		int size,
+		const style::color &bg,
+		const style::color &fg) {
+	x = rtl() ? (outerWidth - x - size) : x;
+
+	PainterHighQualityEnabler hq(p);
+	p.setBrush(bg);
+	p.setPen(Qt::NoPen);
+	p.drawRoundedRect(x, y, size, size, st::buttonRadius, st::buttonRadius);
+
+	PaintSavedMessagesInner(p, x, y, size, bg, fg);
+}
+
+QPixmap EmptyUserpic::GenerateSavedMessages(int size) {
+	return Generate(size, [&](Painter &p) {
+		PaintSavedMessages(p, 0, 0, size, size);
+	});
+}
+
+QPixmap EmptyUserpic::GenerateSavedMessagesRounded(int size) {
+	return Generate(size, [&](Painter &p) {
+		PaintSavedMessagesRounded(p, 0, 0, size, size);
+	});
+}
+
 InMemoryKey EmptyUserpic::uniqueKey() const {
 	const auto first = (uint64(0xFFFFFFFFU) << 32)
 		| anim::getPremultiplied(_color->c);
diff --git a/Telegram/SourceFiles/ui/empty_userpic.h b/Telegram/SourceFiles/ui/empty_userpic.h
index 4c8033750..e177baf4e 100644
--- a/Telegram/SourceFiles/ui/empty_userpic.h
+++ b/Telegram/SourceFiles/ui/empty_userpic.h
@@ -40,6 +40,12 @@ public:
 		int y,
 		int outerWidth,
 		int size);
+	static void PaintSavedMessagesRounded(
+		Painter &p,
+		int x,
+		int y,
+		int outerWidth,
+		int size);
 	static void PaintSavedMessages(
 		Painter &p,
 		int x,
@@ -48,6 +54,16 @@ public:
 		int size,
 		const style::color &bg,
 		const style::color &fg);
+	static void PaintSavedMessagesRounded(
+		Painter &p,
+		int x,
+		int y,
+		int outerWidth,
+		int size,
+		const style::color &bg,
+		const style::color &fg);
+	static QPixmap GenerateSavedMessages(int size);
+	static QPixmap GenerateSavedMessagesRounded(int size);
 
 	~EmptyUserpic();
 
diff --git a/Telegram/SourceFiles/window/notifications_manager.cpp b/Telegram/SourceFiles/window/notifications_manager.cpp
index d2cb7de85..2fde58508 100644
--- a/Telegram/SourceFiles/window/notifications_manager.cpp
+++ b/Telegram/SourceFiles/window/notifications_manager.cpp
@@ -464,6 +464,8 @@ Manager::DisplayOptions Manager::getNotificationOptions(HistoryItem *item) {
 		|| (Global::NotifyView() > dbinvShowPreview);
 	result.hideReplyButton = result.hideMessageText
 		|| !item
+		|| ((item->out() || item->history()->peer->isSelf())
+			&& item->isFromScheduled())
 		|| !item->history()->peer->canWrite()
 		|| (item->history()->peer->slowmodeSecondsLeft() > 0);
 	return result;
@@ -542,20 +544,31 @@ void NativeManager::doShowNotification(
 		int forwardedCount) {
 	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 subtitle = options.hideNameAndPhoto ? QString() : item->notificationHeader();
+	const auto peer = item->history()->peer;
+	const auto scheduled = !options.hideNameAndPhoto
+		&& (item->out() || peer->isSelf())
+		&& item->isFromScheduled();
+	const auto title = options.hideNameAndPhoto
+		? qsl("Telegram Desktop")
+		: (scheduled && peer->isSelf())
+		? tr::lng_notification_reminder(tr::now)
+		: App::peerName(peer);
+	const auto subtitle = options.hideNameAndPhoto
+		? QString()
+		: item->notificationHeader();
 	const auto text = options.hideMessageText
 		? tr::lng_notification_preview(tr::now)
 		: (forwardedCount < 2
-			? (item->groupId() ? tr::lng_in_dlg_album(tr::now) : item->notificationText())
+			? (item->groupId()
+				? tr::lng_in_dlg_album(tr::now)
+				: item->notificationText())
 			: tr::lng_forward_messages(tr::now, lt_count, forwardedCount));
 
 	doShowNativeNotification(
 		item->history()->peer,
 		item->id,
-		title,
-		scheduled ? WrapFromScheduled(subtitle) : subtitle,
+		scheduled ? WrapFromScheduled(title) : title,
+		subtitle,
 		text,
 		options.hideNameAndPhoto,
 		options.hideReplyButton);
diff --git a/Telegram/SourceFiles/window/notifications_manager_default.cpp b/Telegram/SourceFiles/window/notifications_manager_default.cpp
index cafb34912..e2b859684 100644
--- a/Telegram/SourceFiles/window/notifications_manager_default.cpp
+++ b/Telegram/SourceFiles/window/notifications_manager_default.cpp
@@ -13,6 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/widgets/buttons.h"
 #include "ui/widgets/input_fields.h"
 #include "ui/text_options.h"
+#include "ui/emoji_config.h"
+#include "ui/empty_userpic.h"
 #include "dialogs/dialogs_layout.h"
 #include "window/themes/window_theme.h"
 #include "styles/style_dialogs.h"
@@ -74,7 +76,7 @@ Manager::QueuedNotification::QueuedNotification(
 , author(item->notificationHeader())
 , item((forwardedCount < 2) ? item.get() : nullptr)
 , forwardedCount(forwardedCount)
-, fromScheduled(item->out() && item->isFromScheduled()) {
+, fromScheduled((item->out() || peer->isSelf()) && item->isFromScheduled()) {
 }
 
 QPixmap Manager::hiddenUserpicPlaceholder() const {
@@ -680,8 +682,12 @@ void Notification::updateNotifyDisplay() {
 		p.fillRect(0, st::notifyBorderWidth, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder);
 
 		if (!options.hideNameAndPhoto) {
-			_history->peer->loadUserpic();
-			_history->peer->paintUserpicLeft(p, st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), width(), st::notifyPhotoSize);
+			if (_fromScheduled && _history->peer->isSelf()) {
+				Ui::EmptyUserpic::PaintSavedMessages(p, st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), width(), st::notifyPhotoSize);
+			} else {
+				_history->peer->loadUserpic();
+				_history->peer->paintUserpicLeft(p, st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), width(), st::notifyPhotoSize);
+			}
 		} else {
 			p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), manager()->hiddenUserpicPlaceholder());
 		}
@@ -689,7 +695,15 @@ void Notification::updateNotifyDisplay() {
 		int32 itemWidth = w - st::notifyPhotoPos.x() - st::notifyPhotoSize - st::notifyTextLeft - st::notifyClosePos.x() - st::notifyClose.width;
 
 		QRect rectForName(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, itemWidth, st::msgNameFont->height);
+		const auto reminder = _fromScheduled && _history->peer->isSelf();
 		if (!options.hideNameAndPhoto) {
+			if (_fromScheduled) {
+				static const auto emoji = Ui::Emoji::Find(QString::fromUtf8("\xF0\x9F\x93\x85"));
+				const auto size = Ui::Emoji::GetSizeNormal() / cIntRetinaFactor();
+				const auto top = rectForName.top() + (st::msgNameFont->height - size) / 2;
+				Ui::Emoji::Draw(p, emoji, Ui::Emoji::GetSizeNormal(), rectForName.left(), top);
+				rectForName.setLeft(rectForName.left() + size + st::msgNameFont->spacew);
+			}
 			if (const auto chatTypeIcon = Dialogs::Layout::ChatTypeIcon(_history->peer, false, false)) {
 				chatTypeIcon->paint(p, rectForName.topLeft(), w);
 				rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip);
@@ -707,7 +721,9 @@ void Notification::updateNotifyDisplay() {
 			p.setPen(st::dialogsTextFg);
 			p.setFont(st::dialogsTextFont);
 			const auto text = _item
-				? _item->inDialogsText(HistoryItem::DrawInDialog::Normal)
+				? _item->inDialogsText(reminder
+					? HistoryItem::DrawInDialog::WithoutSender
+					: HistoryItem::DrawInDialog::Normal)
 				: ((!_author.isEmpty()
 					? textcmdLink(1, _author)
 					: QString())
@@ -724,10 +740,7 @@ void Notification::updateNotifyDisplay() {
 				0,
 				Qt::LayoutDirectionAuto,
 			};
-			itemTextCache.setText(
-				st::dialogsTextStyle,
-				_fromScheduled ? WrapFromScheduled(text) : text,
-				Options);
+			itemTextCache.setText(st::dialogsTextStyle, text, Options);
 			itemTextCache.drawElided(
 				p,
 				r.left(),
@@ -747,12 +760,15 @@ void Notification::updateNotifyDisplay() {
 		}
 
 		p.setPen(st::dialogsNameFg);
-		if (!options.hideNameAndPhoto) {
-			_history->peer->nameText().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
-		} else {
+		if (options.hideNameAndPhoto) {
 			p.setFont(st::msgNameFont);
 			static QString notifyTitle = st::msgNameFont->elided(qsl("Telegram Desktop"), rectForName.width());
 			p.drawText(rectForName.left(), rectForName.top() + st::msgNameFont->ascent, notifyTitle);
+		} else if (reminder) {
+			p.setFont(st::msgNameFont);
+			p.drawText(rectForName.left(), rectForName.top() + st::msgNameFont->ascent, tr::lng_notification_reminder(tr::now));
+		} else {
+			_history->peer->nameText().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
 		}
 	}
 
diff --git a/Telegram/SourceFiles/window/notifications_utilities.cpp b/Telegram/SourceFiles/window/notifications_utilities.cpp
index 6bfd7a745..43faaf1dd 100644
--- a/Telegram/SourceFiles/window/notifications_utilities.cpp
+++ b/Telegram/SourceFiles/window/notifications_utilities.cpp
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "platform/platform_specific.h"
 #include "core/application.h"
 #include "data/data_peer.h"
+#include "ui/empty_userpic.h"
 #include "styles/style_window.h"
 
 namespace Window {
@@ -45,7 +46,12 @@ QString CachedUserpics::get(const InMemoryKey &key, PeerData *peer) {
 		}
 		v.path = cWorkingDir() + qsl("tdata/temp/") + QString::number(rand_value<uint64>(), 16) + qsl(".png");
 		if (key.first || key.second) {
-			if (_type == Type::Rounded) {
+			if (peer->isSelf()) {
+				const auto method = _type == Type::Rounded
+					? Ui::EmptyUserpic::GenerateSavedMessagesRounded
+					: Ui::EmptyUserpic::GenerateSavedMessages;
+				method(st::notifyMacPhotoSize).save(v.path, "PNG");
+			} else if (_type == Type::Rounded) {
 				peer->saveUserpicRounded(v.path, st::notifyMacPhotoSize);
 			} else {
 				peer->saveUserpic(v.path, st::notifyMacPhotoSize);