Show replies dialog correctly.

This commit is contained in:
John Preston 2020-09-11 18:33:26 +03:00
parent 608d8307d9
commit 4a94a0c438
42 changed files with 345 additions and 58 deletions

View File

@ -1357,6 +1357,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_comments_open_count#one" = "{count} comment";
"lng_comments_open_count#other" = "{count} comments";
"lng_comments_open_none" = "Leave a comment";
"lng_replies_messages" = "Replies";
"lng_archived_name" = "Archived chats";
"lng_archived_add" = "Archive";

View File

@ -86,7 +86,7 @@ void PrivacyExceptionsBoxController::rowClicked(not_null<PeerListRow*> row) {
}
std::unique_ptr<PrivacyExceptionsBoxController::Row> PrivacyExceptionsBoxController::createRow(not_null<History*> history) {
if (history->peer->isSelf()) {
if (history->peer->isSelf() || history->peer->isRepliesChat()) {
return nullptr;
} else if (!history->peer->isUser()
&& !history->peer->isChat()

View File

@ -241,19 +241,31 @@ void FilterChatsPreview::paintEvent(QPaintEvent *e) {
}
for (auto &[history, userpic, button] : _removePeer) {
const auto savedMessages = history->peer->isSelf();
if (savedMessages) {
Ui::EmptyUserpic::PaintSavedMessages(
p,
iconLeft,
top + iconTop,
width(),
st.photoSize);
const auto repliesMessages = history->peer->isRepliesChat();
if (savedMessages || repliesMessages) {
if (savedMessages) {
Ui::EmptyUserpic::PaintSavedMessages(
p,
iconLeft,
top + iconTop,
width(),
st.photoSize);
} else {
Ui::EmptyUserpic::PaintRepliesMessages(
p,
iconLeft,
top + iconTop,
width(),
st.photoSize);
}
p.setPen(st::contactsNameFg);
p.drawTextLeft(
nameLeft,
top + nameTop,
width(),
tr::lng_saved_messages(tr::now));
(savedMessages
? tr::lng_saved_messages(tr::now)
: tr::lng_replies_messages(tr::now)));
} else {
history->peer->paintUserpicLeft(
p,

View File

@ -170,6 +170,8 @@ ExceptionRow::ExceptionRow(not_null<History*> history) : Row(history) {
QString ExceptionRow::generateName() {
return peer()->isSelf()
? tr::lng_saved_messages(tr::now)
: peer()->isRepliesChat()
? tr::lng_replies_messages(tr::now)
: Row::generateName();
}
@ -180,10 +182,13 @@ QString ExceptionRow::generateShortName() {
PaintRoundImageCallback ExceptionRow::generatePaintUserpicCallback() {
const auto peer = this->peer();
const auto saved = peer->isSelf();
const auto replies = peer->isRepliesChat();
auto userpic = saved ? nullptr : ensureUserpicView();
return [=](Painter &p, int x, int y, int outerWidth, int size) mutable {
if (saved) {
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
} else if (replies) {
Ui::EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
} else {
peer->paintUserpicLeft(p, userpic, x, y, outerWidth, size);
}

View File

@ -36,10 +36,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
PaintRoundImageCallback PaintUserpicCallback(
not_null<PeerData*> peer,
bool respectSavedMessagesChat) {
if (respectSavedMessagesChat && peer->isSelf()) {
return [](Painter &p, int x, int y, int outerWidth, int size) {
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
};
if (respectSavedMessagesChat) {
if (peer->isSelf()) {
return [](Painter &p, int x, int y, int outerWidth, int size) {
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
};
} else if (peer->isRepliesChat()) {
return [](Painter &p, int x, int y, int outerWidth, int size) {
Ui::EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
};
}
}
auto userpic = std::shared_ptr<Data::CloudImageView>();
return [=](Painter &p, int x, int y, int outerWidth, int size) mutable {
@ -318,6 +324,8 @@ void PeerListBox::addSelectItem(
const auto respect = _controller->respectSavedMessagesChat();
const auto text = (respect && peer->isSelf())
? tr::lng_saved_short(tr::now)
: (respect && peer->isRepliesChat())
? tr::lng_replies_messages(tr::now)
: peer->shortName();
addSelectItem(
peer->id,
@ -400,14 +408,16 @@ PeerListRow::PeerListRow(not_null<PeerData*> peer, PeerListRowId id)
, _peer(peer)
, _initialized(false)
, _isSearchResult(false)
, _isSavedMessagesChat(false) {
, _isSavedMessagesChat(false)
, _isRepliesMessagesChat(false) {
}
PeerListRow::PeerListRow(PeerListRowId id)
: _id(id)
, _initialized(false)
, _isSearchResult(false)
, _isSavedMessagesChat(false) {
, _isSavedMessagesChat(false)
, _isRepliesMessagesChat(false) {
}
PeerListRow::~PeerListRow() = default;
@ -470,6 +480,8 @@ void PeerListRow::refreshName(const style::PeerListItem &st) {
}
const auto text = _isSavedMessagesChat
? tr::lng_saved_messages(tr::now)
: _isRepliesMessagesChat
? tr::lng_replies_messages(tr::now)
: generateName();
_name.setText(st.nameStyle, text, Ui::NameTextOptions());
}
@ -481,6 +493,8 @@ QString PeerListRow::generateName() {
QString PeerListRow::generateShortName() {
return _isSavedMessagesChat
? tr::lng_saved_short(tr::now)
: _isRepliesMessagesChat
? tr::lng_replies_messages(tr::now)
: peer()->shortName();
}
@ -493,11 +507,14 @@ std::shared_ptr<Data::CloudImageView> PeerListRow::ensureUserpicView() {
PaintRoundImageCallback PeerListRow::generatePaintUserpicCallback() {
const auto saved = _isSavedMessagesChat;
const auto replies = _isRepliesMessagesChat;
const auto peer = this->peer();
auto userpic = saved ? nullptr : ensureUserpicView();
return [=](Painter &p, int x, int y, int outerWidth, int size) mutable {
if (saved) {
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
} else if (replies) {
Ui::EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
} else {
peer->paintUserpicLeft(p, userpic, x, y, outerWidth, size);
}
@ -603,6 +620,8 @@ void PeerListRow::paintDisabledCheckUserpic(
if (_isSavedMessagesChat) {
Ui::EmptyUserpic::PaintSavedMessages(p, userpicLeft, userpicTop, outerWidth, userpicRadius * 2);
} else if (_isRepliesMessagesChat) {
Ui::EmptyUserpic::PaintRepliesMessages(p, userpicLeft, userpicTop, outerWidth, userpicRadius * 2);
} else {
peer()->paintUserpicLeft(p, _userpic, userpicLeft, userpicTop, outerWidth, userpicRadius * 2);
}
@ -731,10 +750,12 @@ void PeerListContent::changeCheckState(
}
void PeerListContent::addRowEntry(not_null<PeerListRow*> row) {
if (_controller->respectSavedMessagesChat()
&& !row->special()
&& row->peer()->isSelf()) {
row->setIsSavedMessagesChat(true);
if (_controller->respectSavedMessagesChat() && !row->special()) {
if (row->peer()->isSelf()) {
row->setIsSavedMessagesChat(true);
} else if (row->peer()->isRepliesChat()) {
row->setIsRepliesMessagesChat(true);
}
}
_rowsById.emplace(row->id(), row);
if (!row->special()) {

View File

@ -146,12 +146,12 @@ public:
void setIsSearchResult(bool isSearchResult) {
_isSearchResult = isSearchResult;
}
bool isSavedMessagesChat() const {
return _isSavedMessagesChat;
}
void setIsSavedMessagesChat(bool isSavedMessagesChat) {
_isSavedMessagesChat = isSavedMessagesChat;
}
void setIsRepliesMessagesChat(bool isRepliesMessagesChat) {
_isRepliesMessagesChat = isRepliesMessagesChat;
}
template <typename UpdateCallback>
void setChecked(
@ -234,6 +234,7 @@ private:
bool _initialized : 1;
bool _isSearchResult : 1;
bool _isSavedMessagesChat : 1;
bool _isRepliesMessagesChat : 1;
};

View File

@ -584,8 +584,7 @@ void ChooseRecipientBoxController::rowClicked(not_null<PeerListRow*> row) {
auto ChooseRecipientBoxController::createRow(
not_null<History*> history) -> std::unique_ptr<Row> {
const auto peer = history->peer;
const auto skip = peer->isChannel()
&& !peer->isMegagroup()
&& !peer->canWrite();
const auto skip = (peer->isBroadcast() && !peer->canWrite())
|| peer->isRepliesChat();
return skip ? nullptr : std::make_unique<Row>(history);
}

View File

@ -203,8 +203,7 @@ public:
protected:
void prepareViewHook() override;
std::unique_ptr<Row> createRow(
not_null<History*> history) override;
std::unique_ptr<Row> createRow(not_null<History*> history) override;
private:
const not_null<Window::SessionNavigation*> _navigation;

View File

@ -635,7 +635,11 @@ void ShareBox::Inner::updateChat(not_null<PeerData*> peer) {
void ShareBox::Inner::updateChatName(
not_null<Chat*> chat,
not_null<PeerData*> peer) {
const auto text = peer->isSelf() ? tr::lng_saved_messages(tr::now) : peer->name;
const auto text = peer->isSelf()
? tr::lng_saved_messages(tr::now)
: peer->isRepliesChat()
? tr::lng_replies_messages(tr::now)
: peer->name;
chat->name.setText(st::shareNameStyle, text, Ui::NameTextOptions());
}

View File

@ -541,6 +541,13 @@ void PeerData::fillNames() {
if (localized != english) {
appendToIndex(localized);
}
} else if (isRepliesChat()) {
const auto english = qsl("Replies");
const auto localized = tr::lng_replies_messages(tr::now);
appendToIndex(english);
if (localized != english) {
appendToIndex(localized);
}
}
} else if (const auto channel = asChannel()) {
appendToIndex(channel->username);
@ -743,6 +750,10 @@ bool PeerData::isBroadcast() const {
return isChannel() ? asChannel()->isBroadcast() : false;
}
bool PeerData::isRepliesChat() const {
return (id == peerFromUser(708513));
}
bool PeerData::canWrite() const {
if (const auto user = asUser()) {
return user->canWrite();

View File

@ -159,6 +159,10 @@ public:
[[nodiscard]] bool isScam() const;
[[nodiscard]] bool isMegagroup() const;
[[nodiscard]] bool isBroadcast() const;
[[nodiscard]] bool isRepliesChat() const;
[[nodiscard]] bool sharedMediaInfo() const {
return isSelf() || isRepliesChat();
}
[[nodiscard]] bool isNotificationsUser() const {
return (id == peerFromUser(333000))

View File

@ -170,6 +170,10 @@ rpl::producer<bool> PeerFlagValue(
rpl::producer<bool> CanWriteValue(UserData *user) {
using namespace rpl::mappers;
if (user->isRepliesChat()) {
return rpl::single(false);
}
return PeerFlagValue(user, MTPDuser::Flag::f_deleted)
| rpl::map(!_1);
}

View File

@ -140,7 +140,7 @@ public:
}
bool canWrite() const {
// Duplicated in Data::CanWriteValue().
return !isInaccessible();
return !isInaccessible() && !isRepliesChat();
}
bool canShareThisContact() const;

View File

@ -819,6 +819,8 @@ void InnerWidget::paintSearchInChat(Painter &p) const {
if (const auto peer = _searchInChat.peer()) {
if (peer->isSelf()) {
paintSearchInSaved(p, top, _searchInChatText);
} else if (peer->isRepliesChat()) {
paintSearchInReplies(p, top, _searchInChatText);
} else {
paintSearchInPeer(p, peer, _searchInChatUserpic, top, _searchInChatText);
}
@ -896,6 +898,16 @@ void InnerWidget::paintSearchInSaved(
paintSearchInFilter(p, paintUserpic, top, nullptr, text);
}
void InnerWidget::paintSearchInReplies(
Painter &p,
int top,
const Ui::Text::String &text) const {
const auto paintUserpic = [&](Painter &p, int x, int y, int size) {
Ui::EmptyUserpic::PaintRepliesMessages(p, x, y, width(), size);
};
paintSearchInFilter(p, paintUserpic, top, nullptr, text);
}
//void InnerWidget::paintSearchInFeed( // #feed
// Painter &p,
// not_null<Data::Feed*> feed,
@ -2359,6 +2371,8 @@ void InnerWidget::refreshSearchInChatLabel() {
if (const auto peer = _searchInChat.peer()) {
if (peer->isSelf()) {
return tr::lng_saved_messages(tr::now);
} else if (peer->isRepliesChat()) {
return tr::lng_replies_messages(tr::now);
}
return peer->name;
//} else if (const auto feed = _searchInChat.feed()) { // #feed

View File

@ -287,6 +287,10 @@ private:
Painter &p,
int top,
const Ui::Text::String &text) const;
void paintSearchInReplies(
Painter &p,
int top,
const Ui::Text::String &text) const;
//void paintSearchInFeed( // #feed
// Painter &p,
// not_null<Data::Feed*> feed,

View File

@ -39,7 +39,7 @@ constexpr int kRecentlyInSeconds = 20 * 3600;
const auto kPsaBadgePrefix = "cloud_lng_badge_psa_";
bool ShowUserBotIcon(not_null<UserData*> user) {
return user->isBot() && !user->isSupport();
return user->isBot() && !user->isSupport() && !user->isRepliesChat();
}
void PaintRowTopRight(Painter &p, const QString &text, QRect &rectForName, bool active, bool selected) {
@ -209,7 +209,8 @@ enum class Flag {
Selected = 0x02,
SearchResult = 0x04,
SavedMessages = 0x08,
AllowUserOnline = 0x10,
RepliesMessages = 0x10,
AllowUserOnline = 0x20,
//FeedSearchResult = 0x10, // #feed
};
inline constexpr bool is_flag_type(Flag) { return true; }
@ -257,6 +258,13 @@ void paintRow(
st::dialogsPadding.y(),
fullWidth,
st::dialogsPhotoSize);
} else if (flags & Flag::RepliesMessages) {
Ui::EmptyUserpic::PaintRepliesMessages(
p,
st::dialogsPadding.x(),
st::dialogsPadding.y(),
fullWidth,
st::dialogsPhotoSize);
} else if (from) {
row->paintUserpic(
p,
@ -433,8 +441,10 @@ void paintRow(
sendStateIcon->paint(p, rectForName.topLeft() + QPoint(rectForName.width(), 0), fullWidth);
}
if (flags & Flag::SavedMessages) {
auto text = tr::lng_saved_messages(tr::now);
if (flags & (Flag::SavedMessages | Flag::RepliesMessages)) {
auto text = (flags & Flag::SavedMessages)
? tr::lng_saved_messages(tr::now)
: tr::lng_replies_messages(tr::now);
const auto textWidth = st::msgNameFont->width(text);
if (textWidth > rectForName.width()) {
text = st::msgNameFont->elided(text, rectForName.width());
@ -701,7 +711,8 @@ void RowPainter::paint(
const auto flags = (active ? Flag::Active : Flag(0))
| (selected ? Flag::Selected : Flag(0))
| (allowUserOnline ? Flag::AllowUserOnline : Flag(0))
| (peer && peer->isSelf() ? Flag::SavedMessages : Flag(0));
| (peer && peer->isSelf() ? Flag::SavedMessages : Flag(0))
| (peer && peer->isRepliesChat() ? Flag::RepliesMessages : Flag(0));
const auto paintItemCallback = [&](int nameleft, int namewidth) {
const auto texttop = st::dialogsPadding.y()
+ st::msgNameFont->height
@ -881,10 +892,13 @@ void RowPainter::paint(
};
const auto showSavedMessages = history->peer->isSelf()
&& !row->searchInChat();
const auto showRepliesMessages = history->peer->isRepliesChat()
&& !row->searchInChat();
const auto flags = (active ? Flag::Active : Flag(0))
| (selected ? Flag::Selected : Flag(0))
| Flag::SearchResult
| (showSavedMessages ? Flag::SavedMessages : Flag(0))/* // #feed
| (showSavedMessages ? Flag::SavedMessages : Flag(0))
| (showRepliesMessages ? Flag::RepliesMessages : Flag(0))/* // #feed
| (row->searchInChat().feed() ? Flag::FeedSearchResult : Flag(0))*/;
paintRow(
p,

View File

@ -1466,6 +1466,8 @@ DialogInfo::Type DialogTypeFromChat(const Chat &chat) {
DialogInfo::Type DialogTypeFromUser(const User &user) {
return user.isSelf
? DialogInfo::Type::Self
: user.isReplies
? DialogInfo::Type::Replies
: user.isBot
? DialogInfo::Type::Bot
: DialogInfo::Type::Personal;

View File

@ -209,6 +209,7 @@ struct User {
int32 id;
bool isBot = false;
bool isSelf = false;
bool isReplies = false;
MTPInputUser input = MTP_inputUserEmpty();
@ -554,6 +555,7 @@ struct DialogInfo {
enum class Type {
Unknown,
Self,
Replies,
Personal,
Bot,
PrivateGroup,

View File

@ -564,6 +564,8 @@ void ControllerObject::fillMessagesState(
result.entityName = dialog->name;
result.entityType = (dialog->type == Data::DialogInfo::Type::Self)
? ProcessingState::EntityType::SavedMessages
: (dialog->type == Data::DialogInfo::Type::Replies)
? ProcessingState::EntityType::RepliesMessages
: ProcessingState::EntityType::Chat;
result.itemIndex = _messagesWritten + progress.itemIndex;
result.itemCount = std::max(_messagesCount, result.itemIndex);

View File

@ -56,6 +56,7 @@ struct ProcessingState {
enum class EntityType {
Chat,
SavedMessages,
RepliesMessages,
Other,
};

View File

@ -2466,6 +2466,7 @@ Result HtmlWriter::writeDialogEnd() {
switch (type) {
case Type::Unknown: return "unknown";
case Type::Self:
case Type::Replies:
case Type::Personal: return "private";
case Type::Bot: return "bot";
case Type::PrivateGroup:
@ -2480,6 +2481,7 @@ Result HtmlWriter::writeDialogEnd() {
switch (type) {
case Type::Unknown:
case Type::Self:
case Type::Replies:
case Type::Personal:
case Type::Bot: return "Deleted Account";
case Type::PrivateGroup:
@ -2494,6 +2496,8 @@ Result HtmlWriter::writeDialogEnd() {
const Data::DialogInfo &dialog) -> QByteArray {
if (dialog.type == Type::Self) {
return "Saved messages";
} else if (dialog.type == Type::Replies) {
return "Replies";
}
return dialog.name;
};
@ -2514,7 +2518,7 @@ Result HtmlWriter::writeDialogEnd() {
+ (outgoing ? " outgoing messages" : " messages");
};
auto userpic = UserpicData{
(_dialog.type == Type::Self
((_dialog.type == Type::Self || _dialog.type == Type::Replies)
? kSavedMessagesColorIndex
: Data::PeerColorIndex(Data::BarePeerId(_dialog.peerId))),
kEntryUserpicSize

View File

@ -1011,6 +1011,7 @@ Result JsonWriter::writeDialogStart(const Data::DialogInfo &data) {
switch (type) {
case Type::Unknown: return "";
case Type::Self: return "saved_messages";
case Type::Replies: return "replies";
case Type::Personal: return "personal_chat";
case Type::Bot: return "bot_chat";
case Type::PrivateGroup: return "private_group";
@ -1026,7 +1027,7 @@ Result JsonWriter::writeDialogStart(const Data::DialogInfo &data) {
? QByteArray()
: prepareArrayItemStart();
block.append(pushNesting(Context::kObject));
if (data.type != Type::Self) {
if (data.type != Type::Self && data.type != Type::Replies) {
block.append(prepareObjectItemStart("name")
+ StringAllowNull(data.name));
}

View File

@ -883,6 +883,7 @@ Result TextWriter::writeDialogEnd() {
switch (type) {
case Type::Unknown: return "(unknown)";
case Type::Self:
case Type::Replies:
case Type::Personal: return "Personal chat";
case Type::Bot: return "Bot chat";
case Type::PrivateGroup: return "Private group";
@ -898,6 +899,8 @@ Result TextWriter::writeDialogEnd() {
Type type) -> QByteArray {
if (dialog.type == Type::Self) {
return "Saved messages";
} else if (dialog.type == Type::Replies) {
return "Replies";
}
const auto name = dialog.name;
if (!name.isEmpty()) {

View File

@ -101,7 +101,9 @@ Content ContentFromState(
? tr::lng_deleted(tr::now)
: (state.entityType == ProcessingState::EntityType::Chat)
? state.entityName
: tr::lng_saved_messages(tr::now)),
: (state.entityType == ProcessingState::EntityType::SavedMessages)
? tr::lng_saved_messages(tr::now)
: tr::lng_replies_messages(tr::now)),
(state.itemCount > 0
? (QString::number(state.itemIndex)
+ " / "

View File

@ -388,7 +388,10 @@ void HistoryInner::enumerateItemsInHistory(History *history, int historytop, Met
}
bool HistoryInner::canHaveFromUserpics() const {
if (_peer->isUser() && !_peer->isSelf() && !Core::App().settings().chatWide()) {
if (_peer->isUser()
&& !_peer->isSelf()
&& !_peer->isRepliesChat()
&& !Core::App().settings().chatWide()) {
return false;
} else if (_peer->isChannel() && !_peer->isMegagroup()) {
return false;

View File

@ -259,7 +259,8 @@ bool HistoryItem::isDiscussionPost() const {
PeerData *HistoryItem::displayFrom() const {
if (const auto sender = discussionPostOriginalSender()) {
return sender;
} else if (history()->peer->isSelf()) {
} else if (history()->peer->isSelf()
|| history()->peer->isRepliesChat()) {
return senderOriginal();
}
return author().get();

View File

@ -1935,7 +1935,9 @@ void HistoryWidget::updateFieldSubmitSettings() {
}
void HistoryWidget::updateNotifyControls() {
if (!_peer || !_peer->isChannel()) return;
if (!_peer || (!_peer->isChannel() && !_peer->isRepliesChat())) {
return;
}
_muteUnmute->setText((_history->mute()
? tr::lng_channel_unmute(tr::now)
@ -3647,7 +3649,10 @@ bool HistoryWidget::isJoinChannel() const {
}
bool HistoryWidget::isMuteUnmute() const {
return _peer && _peer->isChannel() && _peer->asChannel()->isBroadcast() && !_peer->asChannel()->canPublish();
return _peer
&& ((_peer->isBroadcast()
&& !_peer->asChannel()->canPublish())
|| _peer->isRepliesChat());
}
bool HistoryWidget::showRecordButton() const {

View File

@ -429,7 +429,8 @@ bool Element::computeIsAttachToPrevious(not_null<Element*> previous) {
&& mayBeAttached(item)
&& mayBeAttached(prev);
if (possible) {
if (item->history()->peer->isSelf()) {
if (item->history()->peer->isSelf()
|| item->history()->peer->isRepliesChat()) {
return IsAttachedToPreviousInSavedMessages(prev, item);
} else {
return prev->from() == item->from();

View File

@ -1018,6 +1018,11 @@ void Message::unloadHeavyPart() {
_comments = nullptr;
}
bool Message::showForwardsFromSender() const {
const auto peer = message()->history()->peer;
return peer->isSelf() || peer->isRepliesChat();
}
bool Message::hasFromPhoto() const {
if (isHidden()) {
return false;
@ -1032,7 +1037,7 @@ bool Message::hasFromPhoto() const {
return false;
} else if (Core::App().settings().chatWide()) {
return true;
} else if (item->history()->peer->isSelf()) {
} else if (showForwardsFromSender()) {
return item->Has<HistoryMessageForwarded>();
}
return !item->out() && !item->history()->peer->isUser();
@ -1844,7 +1849,7 @@ bool Message::hasFromName() const {
const auto item = message();
return (!hasOutLayout() || item->from()->isMegagroup())
&& (!item->history()->peer->isUser()
|| item->history()->peer->isSelf());
|| showForwardsFromSender());
} break;
case Context::ContactPreview:
return false;
@ -1861,7 +1866,7 @@ bool Message::displayFromName() const {
bool Message::displayForwardedFrom() const {
const auto item = message();
if (item->history()->peer->isSelf()) {
if (showForwardsFromSender()) {
return false;
}
if (const auto forwarded = item->Get<HistoryMessageForwarded>()) {
@ -1885,6 +1890,8 @@ bool Message::hasOutLayout() const {
const auto item = message();
if (item->history()->peer->isSelf()) {
return !item->Has<HistoryMessageForwarded>();
} else if (showForwardsFromSender()) {
return false;
}
return item->out() && !item->isPost();
}
@ -1934,7 +1941,7 @@ bool Message::displayFastShare() const {
return !peer->isMegagroup();
} else if (const auto user = peer->asUser()) {
if (const auto forwarded = item->Get<HistoryMessageForwarded>()) {
return !peer->isSelf()
return !showForwardsFromSender()
&& !item->out()
&& forwarded->originalSender
&& forwarded->originalSender->isChannel()

View File

@ -120,6 +120,7 @@ private:
void refreshEditedBadge();
void fromNameUpdated(int width) const;
[[nodiscard]] bool showForwardsFromSender() const;
[[nodiscard]] TextSelection skipTextSelection(
TextSelection selection) const;
[[nodiscard]] TextSelection unskipTextSelection(

View File

@ -329,7 +329,7 @@ void TopBarWidget::paintTopBar(Painter &p) {
const auto history = _activeChat.history();
const auto folder = _activeChat.folder();
if (folder
|| history->peer->isSelf()
|| history->peer->sharedMediaInfo()
|| (_section == Section::Scheduled)
|| !_customTitleText.isEmpty()) {
// #TODO feed name emoji.
@ -341,7 +341,9 @@ void TopBarWidget::paintTopBar(Painter &p) {
: tr::lng_scheduled_messages(tr::now))
: folder
? folder->chatListName()
: tr::lng_saved_messages(tr::now);
: history->peer->isSelf()
? tr::lng_saved_messages(tr::now)
: tr::lng_replies_messages(tr::now);
const auto textWidth = st::historySavedFont->width(text);
if (availableWidth < textWidth) {
text = st::historySavedFont->elided(text, availableWidth);
@ -467,6 +469,10 @@ void TopBarWidget::infoClicked() {
_controller->showSection(Info::Memento(
_activeChat.peer(),
Info::Section(Storage::SharedMediaType::Photo)));
} else if (_activeChat.peer()->isRepliesChat()) {
_controller->showSection(Info::Memento(
_activeChat.peer(),
Info::Section(Storage::SharedMediaType::Photo)));
} else {
_controller->showPeerInfo(_activeChat.peer());
}

View File

@ -86,7 +86,7 @@ std::vector<std::unique_ptr<ContentMemento>> Memento::DefaultStack(
}
Section Memento::DefaultSection(not_null<PeerData*> peer) {
if (peer->isSelf()) {
if (peer->sharedMediaInfo()) {
return Section(Section::MediaType::Photo);
}
return Section(Section::Type::Profile);
@ -94,7 +94,7 @@ Section Memento::DefaultSection(not_null<PeerData*> peer) {
// // #feed
//Section Memento::DefaultSection(Dialogs::Key key) {
// if (const auto peer = key.peer()) {
// if (peer->isSelf()) {
// if (peer->sharedMediaInfo()) {
// return Section(Section::MediaType::Photo);
// }
// }

View File

@ -575,7 +575,7 @@ rpl::producer<QString> TitleValue(
Unexpected("Bad peer type in Info::TitleValue()");
case Section::Type::Media:
if (peer->isSelf() && isStackBottom) {
if (peer->sharedMediaInfo() && isStackBottom) {
return tr::lng_profile_shared_media();
}
switch (section.mediaType()) {

View File

@ -154,16 +154,16 @@ void WrapWidget::injectActivePeerProfile(not_null<PeerData*> peer) {
? _historyStack.front().section->section().mediaType()
: _controller->section().mediaType();
}();
const auto expectedType = peer->isSelf()
const auto expectedType = peer->sharedMediaInfo()
? Section::Type::Media
: Section::Type::Profile;
const auto expectedMediaType = peer->isSelf()
const auto expectedMediaType = peer->sharedMediaInfo()
? Section::MediaType::Photo
: Section::MediaType::kCount;
if (firstSectionType != expectedType
|| firstSectionMediaType != expectedMediaType
|| firstPeer != peer) {
auto section = peer->isSelf()
auto section = peer->sharedMediaInfo()
? Section(Section::MediaType::Photo)
: Section(Section::Type::Profile);
injectActiveProfileMemento(std::move(
@ -481,7 +481,7 @@ void WrapWidget::addProfileCallsButton() {
const auto peer = key().peer();
const auto user = peer ? peer->asUser() : nullptr;
if (!user
|| user->isSelf()
|| user->sharedMediaInfo()
|| !user->session().serverConfig().phoneCallsEnabled.current()) {
return;
}

View File

@ -264,6 +264,8 @@ void Manager::Private::showNotification(
if (!hideNameAndPhoto && [notification respondsToSelector:@selector(setContentImage:)]) {
auto userpic = peer->isSelf()
? Ui::EmptyUserpic::GenerateSavedMessages(st::notifyMacPhotoSize)
: peer->isRepliesChat()
? Ui::EmptyUserpic::GenerateRepliesMessages(st::notifyMacPhotoSize)
: peer->genUserpic(userpicView, st::notifyMacPhotoSize);
NSImage *img = [qt_mac_create_nsimage(userpic) autorelease];
[notification setContentImage:img];

View File

@ -53,6 +53,10 @@ inline bool IsSelfPeer(PeerData *peer) {
return peer && peer->isSelf();
}
inline bool IsRepliesPeer(PeerData *peer) {
return peer && peer->isRepliesChat();
}
QImage PrepareImage() {
const auto s = kCircleDiameter * cIntRetinaFactor();
auto result = QImage(QSize(s, s), QImage::Format_ARGB32_Premultiplied);
@ -69,6 +73,15 @@ QImage SavedMessagesUserpic() {
return result;
}
QImage RepliesMessagesUserpic() {
auto result = PrepareImage();
Painter paint(&result);
const auto s = result.width();
Ui::EmptyUserpic::PaintRepliesMessages(paint, 0, 0, s, s);
return result;
}
QImage ArchiveUserpic(not_null<Data::Folder*> folder) {
auto result = PrepareImage();
Painter paint(&result);
@ -125,7 +138,7 @@ NSRect PeerRectByIndex(int index) {
}
TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
if (peer->isSelf()) {
if (peer->isSelf() || peer->isRepliesChat()) {
return 0;
}
if (const auto user = peer->asUser()) {
@ -172,10 +185,12 @@ TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
std::vector<std::unique_ptr<Pin>> _pins;
QImage _savedMessages;
QImage _repliesMessages;
QImage _archive;
bool _hasArchive;
bool _selfUnpinned;
bool _repliesUnpinned;
rpl::event_stream<not_null<NSEvent*>> _touches;
rpl::event_stream<not_null<NSPressGestureRecognizer*>> _gestures;
@ -458,6 +473,7 @@ TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
_session = session;
_hasArchive = _selfUnpinned = false;
_savedMessages = SavedMessagesUserpic();
_repliesMessages = RepliesMessagesUserpic();
auto *gesture = [[[NSPressGestureRecognizer alloc]
initWithTarget:self
@ -504,6 +520,9 @@ TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
if (IsSelfPeer(pin->peer)) {
pin->userpic = _savedMessages;
return;
} else if (IsRepliesPeer(pin->peer)) {
pin->userpic = _repliesMessages;
return;
}
auto userpic = PrepareImage();
Painter p(&userpic);
@ -629,6 +648,7 @@ TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
return std::make_unique<Pin>(std::move(pin));
}) | ranges::to_vector;
_selfUnpinned = ranges::none_of(peers, &PeerData::isSelf);
_repliesUnpinned = ranges::none_of(peers, &PeerData::isRepliesChat);
peerChangedLifetime->destroy();
for (const auto &pin : _pins) {
@ -705,6 +725,7 @@ TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
_archive = ArchiveUserpic(f);
}
_savedMessages = SavedMessagesUserpic();
_repliesMessages = RepliesMessagesUserpic();
updateUserpics();
});
}, _lifetime);
@ -771,6 +792,8 @@ TimeId CalculateOnlineTill(not_null<PeerData*> peer) {
return _archive;
} else if (_selfUnpinned) {
return _savedMessages;
} else if (_repliesUnpinned) {
return _repliesMessages;
}
}
return _pins[i]->userpic;

View File

@ -116,7 +116,8 @@ auto BlockPeerBoxController::createRow(not_null<History*> history)
-> std::unique_ptr<BlockPeerBoxController::Row> {
if (!history->peer->isUser()
|| history->peer->isServiceUser()
|| history->peer->isSelf()) {
|| history->peer->isSelf()
|| history->peer->isRepliesChat()) {
return nullptr;
}
auto row = std::make_unique<Row>(history);

View File

@ -91,6 +91,15 @@ void PaintSavedMessagesInner(
}
}
void PaintRepliesMessagesInner(
Painter &p,
int x,
int y,
int size,
const style::color &bg,
const style::color &fg) {
}
template <typename Callback>
[[nodiscard]] QPixmap Generate(int size, Callback callback) {
auto result = QImage(
@ -230,6 +239,76 @@ QPixmap EmptyUserpic::GenerateSavedMessagesRounded(int size) {
});
}
void EmptyUserpic::PaintRepliesMessages(
Painter &p,
int x,
int y,
int outerWidth,
int size) {
const auto &bg = st::historyPeerSavedMessagesBg;
const auto &fg = st::historyPeerUserpicFg;
PaintRepliesMessages(p, x, y, outerWidth, size, bg, fg);
}
void EmptyUserpic::PaintRepliesMessagesRounded(
Painter &p,
int x,
int y,
int outerWidth,
int size) {
const auto &bg = st::historyPeerSavedMessagesBg;
const auto &fg = st::historyPeerUserpicFg;
PaintRepliesMessagesRounded(p, x, y, outerWidth, size, bg, fg);
}
void EmptyUserpic::PaintRepliesMessages(
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);
PaintRepliesMessagesInner(p, x, y, size, bg, fg);
}
void EmptyUserpic::PaintRepliesMessagesRounded(
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);
PaintRepliesMessagesInner(p, x, y, size, bg, fg);
}
QPixmap EmptyUserpic::GenerateRepliesMessages(int size) {
return Generate(size, [&](Painter &p) {
PaintRepliesMessages(p, 0, 0, size, size);
});
}
QPixmap EmptyUserpic::GenerateRepliesMessagesRounded(int size) {
return Generate(size, [&](Painter &p) {
PaintRepliesMessagesRounded(p, 0, 0, size, size);
});
}
InMemoryKey EmptyUserpic::uniqueKey() const {
const auto first = (uint64(0xFFFFFFFFU) << 32)
| anim::getPremultiplied(_color->c);

View File

@ -65,6 +65,37 @@ public:
static QPixmap GenerateSavedMessages(int size);
static QPixmap GenerateSavedMessagesRounded(int size);
static void PaintRepliesMessages(
Painter &p,
int x,
int y,
int outerWidth,
int size);
static void PaintRepliesMessagesRounded(
Painter &p,
int x,
int y,
int outerWidth,
int size);
static void PaintRepliesMessages(
Painter &p,
int x,
int y,
int outerWidth,
int size,
const style::color &bg,
const style::color &fg);
static void PaintRepliesMessagesRounded(
Painter &p,
int x,
int y,
int outerWidth,
int size,
const style::color &bg,
const style::color &fg);
static QPixmap GenerateRepliesMessages(int size);
static QPixmap GenerateRepliesMessagesRounded(int size);
~EmptyUserpic();
private:

View File

@ -675,6 +675,13 @@ void UserpicButton::paintEvent(QPaintEvent *e) {
photoPosition.y(),
width(),
_st.photoSize);
} else if (showRepliesMessages()) {
Ui::EmptyUserpic::PaintRepliesMessages(
p,
photoPosition.x(),
photoPosition.y(),
width(),
_st.photoSize);
} else {
if (_a_appearance.animating()) {
p.drawPixmapLeft(photoPosition, width(), _oldUserpic);
@ -1032,6 +1039,10 @@ bool UserpicButton::showSavedMessages() const {
return _showSavedMessagesOnSelf && _peer && _peer->isSelf();
}
bool UserpicButton::showRepliesMessages() const {
return _showSavedMessagesOnSelf && _peer && _peer->isRepliesChat();
}
void UserpicButton::startChangeOverlayAnimation() {
auto over = isOver() || isDown();
_changeOverlayShown.start(

View File

@ -222,6 +222,7 @@ private:
void updateCursor();
void updateVideo();
bool showSavedMessages() const;
bool showRepliesMessages() const;
void checkStreamedIsStarted();
bool createStreamingObjects(not_null<PhotoData*> photo);
void clearStreaming();

View File

@ -66,6 +66,11 @@ QString CachedUserpics::get(
? Ui::EmptyUserpic::GenerateSavedMessagesRounded
: Ui::EmptyUserpic::GenerateSavedMessages;
method(st::notifyMacPhotoSize).save(v.path, "PNG");
} else if (peer->isRepliesChat()) {
const auto method = (_type == Type::Rounded)
? Ui::EmptyUserpic::GenerateRepliesMessagesRounded
: Ui::EmptyUserpic::GenerateRepliesMessages;
method(st::notifyMacPhotoSize).save(v.path, "PNG");
} else if (_type == Type::Rounded) {
peer->saveUserpicRounded(view, v.path, st::notifyMacPhotoSize);
} else {