Improve empty group display.
This commit is contained in:
		
							parent
							
								
									69b1f6c4e1
								
							
						
					
					
						commit
						ebc2043055
					
				
					 8 changed files with 75 additions and 23 deletions
				
			
		| 
						 | 
				
			
			@ -586,6 +586,7 @@ HistoryItem *History::addNewToLastBlock(
 | 
			
		|||
		applyMessageChanges(item, msg);
 | 
			
		||||
	}
 | 
			
		||||
	const auto result = addNewItem(item, newUnreadMessage);
 | 
			
		||||
	checkForLoadedAtTop(result);
 | 
			
		||||
	if (type == NewMessageLast) {
 | 
			
		||||
		// When we add just one last item, like we do while loading dialogs,
 | 
			
		||||
		// we want to remove a single added grouped media, otherwise it will
 | 
			
		||||
| 
						 | 
				
			
			@ -599,6 +600,22 @@ HistoryItem *History::addNewToLastBlock(
 | 
			
		|||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void History::checkForLoadedAtTop(not_null<HistoryItem*> added) {
 | 
			
		||||
	if (peer->isChat()) {
 | 
			
		||||
		if (added->isGroupEssential() && !added->isGroupMigrate()) {
 | 
			
		||||
			// We added the first message about group creation.
 | 
			
		||||
			_loadedAtTop = true;
 | 
			
		||||
			addEdgesToSharedMedia();
 | 
			
		||||
		}
 | 
			
		||||
	} else if (peer->isChannel()) {
 | 
			
		||||
		if (added->id == 1) {
 | 
			
		||||
			_loadedAtTop = true;
 | 
			
		||||
			checkJoinedMessage();
 | 
			
		||||
			addEdgesToSharedMedia();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HistoryItem *History::addToHistory(const MTPMessage &msg) {
 | 
			
		||||
	const auto detachExistingItem = false;
 | 
			
		||||
	return createItem(msg, detachExistingItem);
 | 
			
		||||
| 
						 | 
				
			
			@ -2130,7 +2147,7 @@ auto History::computeChatListMessageFromLast() const
 | 
			
		|||
	// about migration in the chats list and display the last
 | 
			
		||||
	// non-migration message from the original legacy group.
 | 
			
		||||
	const auto last = lastMessage();
 | 
			
		||||
	if (!last || !last->isGroupEssential() || !last->isEmpty()) {
 | 
			
		||||
	if (!last || !last->isGroupMigrate()) {
 | 
			
		||||
		return _lastMessage;
 | 
			
		||||
	}
 | 
			
		||||
	if (const auto chat = peer->asChat()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2216,7 +2233,7 @@ void History::setFakeChatListMessageFrom(const MTPmessages_Messages &data) {
 | 
			
		|||
		}
 | 
			
		||||
	});
 | 
			
		||||
	const auto last = lastMessage();
 | 
			
		||||
	if (!last || !last->isGroupEssential() || !last->isEmpty()) {
 | 
			
		||||
	if (!last || !last->isGroupMigrate()) {
 | 
			
		||||
		// Last message is good enough.
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -2239,7 +2256,7 @@ void History::setFakeChatListMessageFrom(const MTPmessages_Messages &data) {
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	const auto item = owner().addNewMessage(*other, NewMessageExisting);
 | 
			
		||||
	if (!item || (item->isGroupEssential() && item->isEmpty())) {
 | 
			
		||||
	if (!item || item->isGroupMigrate()) {
 | 
			
		||||
		// Not better than the last one.
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -2732,19 +2749,37 @@ bool History::isEmpty() const {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
bool History::isDisplayedEmpty() const {
 | 
			
		||||
	if (!loadedAtTop() || !loadedAtBottom()) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	const auto first = findFirstNonEmpty();
 | 
			
		||||
	if (!first) {
 | 
			
		||||
		return true;
 | 
			
		||||
	} else if (!first->data()->isGroupEssential()) {
 | 
			
		||||
		return false;
 | 
			
		||||
	} else if (const auto chat = peer->asChat()) {
 | 
			
		||||
		// For legacy chats we want to show the chat with only first
 | 
			
		||||
		// message about you creating the group as an empty chat with
 | 
			
		||||
		// a nice information about the group features.
 | 
			
		||||
		return chat->amCreator() && (findLastNonEmpty() == first);
 | 
			
		||||
	} else {
 | 
			
		||||
	}
 | 
			
		||||
	const auto chat = peer->asChat();
 | 
			
		||||
	if (!chat || !chat->amCreator()) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// For legacy chats we want to show the chat with only
 | 
			
		||||
	// messages about you creating the group and maybe about you
 | 
			
		||||
	// changing the group photo as an empty chat with
 | 
			
		||||
	// a nice information about the group features.
 | 
			
		||||
	if (nonEmptyCountMoreThan(2)) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	const auto isChangePhoto = [](not_null<HistoryItem*> item) {
 | 
			
		||||
		if (const auto media = item->media()) {
 | 
			
		||||
			return (media->photo() != nullptr) && !item->toHistoryMessage();
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	};
 | 
			
		||||
	const auto last = findLastNonEmpty();
 | 
			
		||||
	if (first == last) {
 | 
			
		||||
		return first->data()->isGroupEssential()
 | 
			
		||||
			|| isChangePhoto(first->data());
 | 
			
		||||
	}
 | 
			
		||||
	return first->data()->isGroupEssential() && isChangePhoto(last->data());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto History::findFirstNonEmpty() const -> Element* {
 | 
			
		||||
| 
						 | 
				
			
			@ -2769,6 +2804,21 @@ auto History::findLastNonEmpty() const -> Element* {
 | 
			
		|||
	return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool History::nonEmptyCountMoreThan(int count) const {
 | 
			
		||||
	Expects(count >= 0);
 | 
			
		||||
 | 
			
		||||
	for (const auto &block : blocks) {
 | 
			
		||||
		for (const auto &element : block->messages) {
 | 
			
		||||
			if (!element->data()->isEmpty()) {
 | 
			
		||||
				if (!count--) {
 | 
			
		||||
					return true;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool History::hasOrphanMediaGroupPart() const {
 | 
			
		||||
	if (loadedAtTop() || !loadedAtBottom()) {
 | 
			
		||||
		return false;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -396,6 +396,7 @@ private:
 | 
			
		|||
		return _buildingFrontBlock != nullptr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void checkForLoadedAtTop(not_null<HistoryItem*> added);
 | 
			
		||||
	void mainViewRemoved(
 | 
			
		||||
		not_null<HistoryBlock*> block,
 | 
			
		||||
		not_null<Element*> view);
 | 
			
		||||
| 
						 | 
				
			
			@ -439,6 +440,7 @@ private:
 | 
			
		|||
 | 
			
		||||
	HistoryItem *lastAvailableMessage() const;
 | 
			
		||||
	void getNextFirstUnreadMessage();
 | 
			
		||||
	bool nonEmptyCountMoreThan(int count) const;
 | 
			
		||||
 | 
			
		||||
	// Creates if necessary a new block for adding item.
 | 
			
		||||
	// Depending on isBuildingFrontBlock() gets front or back block.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -543,7 +543,8 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
 | 
			
		|||
	auto clip = e->rect();
 | 
			
		||||
	auto ms = getms();
 | 
			
		||||
 | 
			
		||||
	bool historyDisplayedEmpty = (_history->isDisplayedEmpty() && (!_migrated || _migrated->isDisplayedEmpty()));
 | 
			
		||||
	const auto historyDisplayedEmpty = _history->isDisplayedEmpty()
 | 
			
		||||
		&& (!_migrated || _migrated->isDisplayedEmpty());
 | 
			
		||||
	bool noHistoryDisplayed = _firstLoading || historyDisplayedEmpty;
 | 
			
		||||
	if (!_firstLoading && _botAbout && !_botAbout->info->text.isEmpty() && _botAbout->height > 0) {
 | 
			
		||||
		if (clip.y() < _botAbout->rect.y() + _botAbout->rect.height() && clip.y() + clip.height() > _botAbout->rect.y()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -561,6 +562,8 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
 | 
			
		|||
		}
 | 
			
		||||
	} else if (historyDisplayedEmpty) {
 | 
			
		||||
		paintEmpty(p, width(), height());
 | 
			
		||||
	} else {
 | 
			
		||||
		_emptyPainter = nullptr;
 | 
			
		||||
	}
 | 
			
		||||
	if (!noHistoryDisplayed) {
 | 
			
		||||
		auto readMentions = base::flat_set<not_null<HistoryItem*>>();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,7 +55,6 @@ public:
 | 
			
		|||
	void messagesReceivedDown(PeerData *peer, const QVector<MTPMessage> &messages);
 | 
			
		||||
 | 
			
		||||
	TextWithEntities getSelectedText() const;
 | 
			
		||||
	void paintEmpty(Painter &p, int width, int height);
 | 
			
		||||
 | 
			
		||||
	void touchScrollUpdated(const QPoint &screenPos);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -201,6 +200,8 @@ private:
 | 
			
		|||
	std::unique_ptr<QMimeData> prepareDrag();
 | 
			
		||||
	void performDrag();
 | 
			
		||||
 | 
			
		||||
	void paintEmpty(Painter &p, int width, int height);
 | 
			
		||||
 | 
			
		||||
	QPoint mapPointToItem(QPoint p, const Element *view) const;
 | 
			
		||||
	QPoint mapPointToItem(QPoint p, const HistoryItem *item) const;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -462,7 +462,7 @@ bool HistoryItem::canDelete() const {
 | 
			
		|||
	}
 | 
			
		||||
	auto channel = _history->peer->asChannel();
 | 
			
		||||
	if (!channel) {
 | 
			
		||||
		return !(_flags & MTPDmessage_ClientFlag::f_is_group_essential);
 | 
			
		||||
		return !isGroupMigrate();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (id == 1) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -137,6 +137,9 @@ public:
 | 
			
		|||
	bool isGroupEssential() const {
 | 
			
		||||
		return _flags & MTPDmessage_ClientFlag::f_is_group_essential;
 | 
			
		||||
	}
 | 
			
		||||
	bool isGroupMigrate() const {
 | 
			
		||||
		return isGroupEssential() && isEmpty();
 | 
			
		||||
	}
 | 
			
		||||
	bool hasViews() const {
 | 
			
		||||
		return _flags & MTPDmessage::Flag::f_views;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6554,13 +6554,6 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
 | 
			
		|||
		if (_pinnedBar && !_pinnedBar->cancel->isHidden()) {
 | 
			
		||||
			drawPinnedBar(p);
 | 
			
		||||
		}
 | 
			
		||||
		if (_scroll->isHidden() && _history) {
 | 
			
		||||
			p.setClipRect(_scroll->geometry());
 | 
			
		||||
			_list->paintEmpty(
 | 
			
		||||
				p,
 | 
			
		||||
				width(),
 | 
			
		||||
				height() - _field->height() - 2 * st::historySendPadding);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		const auto w = st::msgServiceFont->width(lang(lng_willbe_history))
 | 
			
		||||
			+ st::msgPadding.left()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -557,7 +557,7 @@ void EmptyPainter::fillAboutGroup() {
 | 
			
		|||
		text.setText(
 | 
			
		||||
			st::serviceTextStyle,
 | 
			
		||||
			content,
 | 
			
		||||
			Ui::ItemTextServiceOptions());
 | 
			
		||||
			Ui::NameTextOptions());
 | 
			
		||||
	};
 | 
			
		||||
	setText(_header, lang(lng_group_about_header));
 | 
			
		||||
	setText(_text, lang(lng_group_about_text));
 | 
			
		||||
| 
						 | 
				
			
			@ -603,7 +603,7 @@ void EmptyPainter::paint(Painter &p, int width, int height) {
 | 
			
		|||
		+ st::historyGroupAboutSkip * int(_phrases.size() - 1)
 | 
			
		||||
		+ padding.bottom();
 | 
			
		||||
	const auto bubbleLeft = (width - bubbleWidth) / 2;
 | 
			
		||||
	const auto bubbleTop = (height - bubbleHeight) / 3;
 | 
			
		||||
	const auto bubbleTop = (height - bubbleHeight) / 2;
 | 
			
		||||
 | 
			
		||||
	ServiceMessagePainter::paintBubble(
 | 
			
		||||
		p,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue