From 6726826c17824c7ceacfac47a94f6ff616c35ec2 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Mon, 5 Feb 2018 23:19:51 +0300
Subject: [PATCH] Display empty feed placeholder.

---
 Telegram/Resources/langs/lang.strings         |  1 +
 Telegram/SourceFiles/data/data_messages.cpp   |  1 +
 Telegram/SourceFiles/data/data_sparse_ids.cpp |  3 ++
 .../history/feed/history_feed_section.cpp     | 49 +++++++++++++++++++
 .../history/feed/history_feed_section.h       |  5 ++
 Telegram/SourceFiles/history/history_item.cpp |  6 +++
 Telegram/SourceFiles/history/history_item.h   |  5 ++
 .../SourceFiles/history/history_widget.cpp    | 23 +++++++--
 .../history/view/history_view_list_widget.cpp | 11 ++++-
 .../history/view/history_view_list_widget.h   |  1 +
 Telegram/SourceFiles/ui/special_buttons.cpp   |  5 +-
 11 files changed, 102 insertions(+), 8 deletions(-)

diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index c427185d9..136243a7a 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -1423,6 +1423,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 "lng_feed_ungroup" = "Ungroup from feed";
 "lng_feed_channel_added" = "Channel added to your feed.";
 "lng_feed_channel_removed" = "Channel removed from your feed.";
+"lng_feed_no_messages" = "No messages in this feed yet";
 
 "lng_info_feed_title" = "Feed Info";
 
diff --git a/Telegram/SourceFiles/data/data_messages.cpp b/Telegram/SourceFiles/data/data_messages.cpp
index f3ab4a6fd..460389469 100644
--- a/Telegram/SourceFiles/data/data_messages.cpp
+++ b/Telegram/SourceFiles/data/data_messages.cpp
@@ -332,6 +332,7 @@ bool MessagesSliceBuilder::removeFromChannel(ChannelId channelId) {
 		}
 	}
 	_skippedBefore = _skippedAfter = base::none;
+	checkInsufficient();
 	return true;
 }
 
diff --git a/Telegram/SourceFiles/data/data_sparse_ids.cpp b/Telegram/SourceFiles/data/data_sparse_ids.cpp
index 774f9d28d..bf55cb4cb 100644
--- a/Telegram/SourceFiles/data/data_sparse_ids.cpp
+++ b/Telegram/SourceFiles/data/data_sparse_ids.cpp
@@ -237,6 +237,9 @@ bool SparseIdsSliceBuilder::removeOne(MsgId messageId) {
 			changed = true;
 		}
 	}
+	if (changed) {
+		checkInsufficient();
+	}
 	return changed;
 }
 
diff --git a/Telegram/SourceFiles/history/feed/history_feed_section.cpp b/Telegram/SourceFiles/history/feed/history_feed_section.cpp
index d8bf5b075..a8c91d2e5 100644
--- a/Telegram/SourceFiles/history/feed/history_feed_section.cpp
+++ b/Telegram/SourceFiles/history/feed/history_feed_section.cpp
@@ -13,6 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/view/history_view_message.h"
 #include "history/view/history_view_service_message.h"
 #include "history/history_item.h"
+#include "history/history_service.h"
+#include "history/history_inner_widget.h"
 #include "core/event_filter.h"
 #include "lang/lang_keys.h"
 #include "ui/widgets/buttons.h"
@@ -380,7 +382,34 @@ base::optional<int> Widget::listUnreadBarView(
 	return base::make_optional(int(minimal - begin(elements)));
 }
 
+void Widget::validateEmptyTextItem() {
+	if (!_inner->isEmpty()) {
+		_emptyTextView = nullptr;
+		_emptyTextItem = nullptr;
+		update();
+		return;
+	} else if (_emptyTextItem) {
+		return;
+	}
+	const auto channels = _feed->channels();
+	if (channels.empty()) {
+		return;
+	}
+	const auto history = channels[0];
+	_emptyTextItem.reset(new HistoryService(
+		history,
+		clientMsgId(),
+		unixtime(),
+		{ lang(lng_feed_no_messages) }));
+	_emptyTextView = _emptyTextItem->createView(
+		HistoryInner::ElementDelegate());
+	updateControlsGeometry();
+	update();
+}
+
 void Widget::listContentRefreshed() {
+	validateEmptyTextItem();
+
 	if (!_nextAnimatedScrollPosition) {
 		return;
 	}
@@ -457,6 +486,10 @@ void Widget::updateControlsGeometry() {
 		contentWidth,
 		_showNext->height());
 	_showNext->setGeometry(fullWidthButtonRect);
+
+	if (_emptyTextView) {
+		_emptyTextView->resizeGetHeight(width());
+	}
 }
 
 void Widget::paintEvent(QPaintEvent *e) {
@@ -475,6 +508,22 @@ void Widget::paintEvent(QPaintEvent *e) {
 	_scrollDownShown.step(ms);
 
 	SectionWidget::PaintBackground(this, e);
+
+	if (_emptyTextView) {
+		Painter p(this);
+
+		const auto clip = e->rect();
+		const auto left = 0;
+		const auto top = (height()
+			- _showNext->height()
+			- _emptyTextView->height()) / 2;
+		p.translate(left, top);
+		_emptyTextView->draw(
+			p,
+			clip.translated(-left, -top),
+			TextSelection(),
+			getms());
+	}
 }
 
 void Widget::onScroll() {
diff --git a/Telegram/SourceFiles/history/feed/history_feed_section.h b/Telegram/SourceFiles/history/feed/history_feed_section.h
index 08ebe6849..ea119c9e6 100644
--- a/Telegram/SourceFiles/history/feed/history_feed_section.h
+++ b/Telegram/SourceFiles/history/feed/history_feed_section.h
@@ -11,6 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "window/section_widget.h"
 #include "window/section_memento.h"
 #include "data/data_feed.h"
+#include "history/history_item.h"
+#include "history/admin_log/history_admin_log_item.h"
 
 namespace Ui {
 class ScrollArea;
@@ -103,6 +105,7 @@ private:
 	void restoreState(not_null<Memento*> memento);
 	void showAtPosition(Data::MessagePosition position);
 	bool showAtPositionNow(Data::MessagePosition position);
+	void validateEmptyTextItem();
 
 	void setupScrollDownButton();
 	void scrollDownClicked();
@@ -122,6 +125,8 @@ private:
 	object_ptr<Ui::FlatButton> _showNext;
 	bool _skipScrollEvent = false;
 	bool _undefinedAroundPosition = false;
+	std::unique_ptr<HistoryItem, HistoryItem::Destroyer> _emptyTextItem;
+	std::unique_ptr<HistoryView::Element> _emptyTextView;
 
 	base::optional<Data::MessagePosition> _nextAnimatedScrollPosition;
 	int _nextAnimatedScrollDelta = 0;
diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp
index ef20a27cd..71014e4e6 100644
--- a/Telegram/SourceFiles/history/history_item.cpp
+++ b/Telegram/SourceFiles/history/history_item.cpp
@@ -71,6 +71,12 @@ not_null<HistoryItem*> CreateUnsupportedMessage(
 
 } // namespace
 
+void HistoryItem::HistoryItem::Destroyer::operator()(HistoryItem *value) {
+	if (value) {
+		value->destroy();
+	}
+}
+
 HistoryItem::HistoryItem(
 	not_null<History*> history,
 	MsgId id,
diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h
index 177096626..e697ead2a 100644
--- a/Telegram/SourceFiles/history/history_item.h
+++ b/Telegram/SourceFiles/history/history_item.h
@@ -60,6 +60,11 @@ public:
 		not_null<History*> history,
 		const MTPMessage &message);
 
+	struct Destroyer {
+		void operator()(HistoryItem *value);
+
+	};
+
 	virtual void dependencyItemRemoved(HistoryItem *dependency) {
 	}
 	virtual bool updateDependencyItem() {
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index f911b8f04..d6a3ceaa1 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -6690,14 +6690,27 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
 			HistoryView::paintEmpty(p, width(), height() - _field->height() - 2 * st::historySendPadding);
 		}
 	} else {
-		style::font font(st::msgServiceFont);
-		int32 w = font->width(lang(lng_willbe_history)) + st::msgPadding.left() + st::msgPadding.right(), h = font->height + st::msgServicePadding.top() + st::msgServicePadding.bottom() + 2;
-		QRect tr((width() - w) / 2, (height() - _field->height() - 2 * st::historySendPadding - h) / 2, w, h);
+		const auto w = st::msgServiceFont->width(lang(lng_willbe_history))
+			+ st::msgPadding.left()
+			+ st::msgPadding.right();
+		const auto h = st::msgServiceFont->height
+			+ st::msgServicePadding.top()
+			+ st::msgServicePadding.bottom();
+		const auto tr = QRect(
+			(width() - w) / 2,
+			st::msgServiceMargin.top() + (height()
+				- _field->height()
+				- 2 * st::historySendPadding
+				- h
+				- st::msgServiceMargin.top()
+				- st::msgServiceMargin.bottom()) / 2,
+			w,
+			h);
 		HistoryView::ServiceMessagePainter::paintBubble(p, tr.x(), tr.y(), tr.width(), tr.height());
 
 		p.setPen(st::msgServiceFg);
-		p.setFont(font->f);
-		p.drawText(tr.left() + st::msgPadding.left(), tr.top() + st::msgServicePadding.top() + 1 + font->ascent, lang(lng_willbe_history));
+		p.setFont(st::msgServiceFont->f);
+		p.drawTextLeft(tr.left() + st::msgPadding.left(), tr.top() + st::msgServicePadding.top(), width(), lang(lng_willbe_history));
 	}
 }
 
diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp
index 3effa75fe..ebe2e1fd4 100644
--- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp
@@ -463,7 +463,11 @@ not_null<Element*> ListWidget::enforceViewForItem(
 void ListWidget::updateAroundPositionFromRows() {
 	_aroundIndex = findNearestItem(_aroundPosition);
 	if (_aroundIndex >= 0) {
-		_aroundPosition = _items[_aroundIndex]->data()->position();
+		const auto newPosition = _items[_aroundIndex]->data()->position();
+		if (_aroundPosition != newPosition) {
+			_aroundPosition = newPosition;
+			crl::on_main(this, [=] { refreshViewer(); });
+		}
 	}
 }
 
@@ -923,6 +927,10 @@ bool ListWidget::loadedAtBottom() const {
 	return _slice.skippedAfter && (*_slice.skippedAfter == 0);
 }
 
+bool ListWidget::isEmpty() const {
+	return loadedAtTop() && loadedAtBottom() && (_itemsHeight == 0);
+}
+
 int ListWidget::itemMinimalHeight() const {
 	return st::msgMarginTopAttached
 		+ st::msgPhotoSize
@@ -2235,6 +2243,7 @@ void ListWidget::refreshAttachmentsFromTill(int from, int till) {
 	Expects(from >= 0 && from <= till && till <= int(_items.size()));
 
 	if (from == till) {
+		updateSize();
 		return;
 	}
 	auto view = _items[from].get();
diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h
index 36682c249..b9a908e8a 100644
--- a/Telegram/SourceFiles/history/view/history_view_list_widget.h
+++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h
@@ -159,6 +159,7 @@ public:
 	bool loadedAtTop() const;
 	bool loadedAtBottomKnown() const;
 	bool loadedAtBottom() const;
+	bool isEmpty() const;
 
 	// AbstractTooltipShower interface
 	QString tooltipText() const override;
diff --git a/Telegram/SourceFiles/ui/special_buttons.cpp b/Telegram/SourceFiles/ui/special_buttons.cpp
index affd69847..98c045e45 100644
--- a/Telegram/SourceFiles/ui/special_buttons.cpp
+++ b/Telegram/SourceFiles/ui/special_buttons.cpp
@@ -860,10 +860,11 @@ void FeedUserpicButton::checkParts() {
 
 bool FeedUserpicButton::partsAreValid() const {
 	const auto &channels = _feed->channels();
-	if (std::min(int(channels.size()), 4) != _parts.size()) {
+	const auto count = std::min(int(channels.size()), 4);
+	if (count != _parts.size()) {
 		return false;
 	}
-	for (auto i = 0; i != 4; ++i) {
+	for (auto i = 0; i != count; ++i) {
 		if (channels[i]->peer != _parts[i].channel) {
 			return false;
 		}