mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 22:54:01 +02:00
Handle correctly comment links for public channels.
This commit is contained in:
parent
7862443fcb
commit
61d89113d4
8 changed files with 181 additions and 132 deletions
|
@ -267,21 +267,31 @@ bool ResolveUsername(
|
|||
auto post = (start == qsl("startgroup"))
|
||||
? ShowAtProfileMsgId
|
||||
: ShowAtUnreadMsgId;
|
||||
auto postParam = params.value(qsl("post"));
|
||||
if (auto postId = postParam.toInt()) {
|
||||
const auto postParam = params.value(qsl("post"));
|
||||
if (const auto postId = postParam.toInt()) {
|
||||
post = postId;
|
||||
}
|
||||
const auto commentParam = params.value(qsl("comment"));
|
||||
const auto commentId = commentParam.toInt();
|
||||
const auto gameParam = params.value(qsl("game"));
|
||||
if (!gameParam.isEmpty() && valid(gameParam)) {
|
||||
startToken = gameParam;
|
||||
post = ShowAtGameShareMsgId;
|
||||
}
|
||||
const auto clickFromMessageId = context.value<FullMsgId>();
|
||||
controller->content()->openPeerByName(
|
||||
domain,
|
||||
post,
|
||||
startToken,
|
||||
clickFromMessageId);
|
||||
if (commentId) {
|
||||
controller->content()->openCommentByName(
|
||||
domain,
|
||||
post,
|
||||
commentId,
|
||||
clickFromMessageId);
|
||||
} else {
|
||||
controller->content()->openPeerByName(
|
||||
domain,
|
||||
post,
|
||||
startToken,
|
||||
clickFromMessageId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -300,7 +310,14 @@ bool ResolvePrivatePost(
|
|||
if (!channelId || !IsServerMsgId(msgId)) {
|
||||
return false;
|
||||
}
|
||||
const auto clickFromMessageId = context.value<FullMsgId>();
|
||||
const auto done = crl::guard(controller, [=](not_null<PeerData*> peer) {
|
||||
auto params = Window::SectionShow{
|
||||
Window::SectionShow::Way::Forward
|
||||
};
|
||||
params.origin = Window::SectionShow::OriginMessage{
|
||||
clickFromMessageId
|
||||
};
|
||||
controller->showPeerHistory(
|
||||
peer->id,
|
||||
Window::SectionShow::Way::Forward,
|
||||
|
@ -545,8 +562,9 @@ QString TryConvertUrlToLocal(QString url) {
|
|||
} else if (auto bgMatch = regex_match(qsl("^bg/([a-zA-Z0-9\\.\\_\\-]+)(\\?(.+)?)?$"), query, matchOptions)) {
|
||||
const auto params = bgMatch->captured(3);
|
||||
return qsl("tg://bg?slug=") + bgMatch->captured(1) + (params.isEmpty() ? QString() : '&' + params);
|
||||
} else if (auto postMatch = regex_match(qsl("^c/(\\-?\\d+)/(\\d+)(#|$)"), query, matchOptions)) {
|
||||
return qsl("tg://privatepost?channel=%1&post=%2").arg(postMatch->captured(1)).arg(postMatch->captured(2));
|
||||
} else if (auto postMatch = regex_match(qsl("^c/(\\-?\\d+)/(\\d+)(/?\\?|/?$)"), query, matchOptions)) {
|
||||
auto params = query.mid(postMatch->captured(0).size()).toString();
|
||||
return qsl("tg://privatepost?channel=%1&post=%2").arg(postMatch->captured(1)).arg(postMatch->captured(2)) + (params.isEmpty() ? QString() : '&' + params);
|
||||
} else if (auto usernameMatch = regex_match(qsl("^([a-zA-Z0-9\\.\\_]+)(/?\\?|/?$|/(\\d+)/?(?:\\?|$))"), query, matchOptions)) {
|
||||
auto params = query.mid(usernameMatch->captured(0).size()).toString();
|
||||
auto postParam = QString();
|
||||
|
|
|
@ -2029,7 +2029,7 @@ bool Message::displayRightActionComments() const {
|
|||
return data()->repliesAreComments()
|
||||
&& media()
|
||||
&& media()->isDisplayed()
|
||||
&& media()->customInfoLayout();
|
||||
&& !hasBubble();
|
||||
}
|
||||
|
||||
std::optional<QSize> Message::rightActionSize() const {
|
||||
|
|
|
@ -83,9 +83,16 @@ bool CanSendFiles(not_null<const QMimeData*> data) {
|
|||
|
||||
} // namespace
|
||||
|
||||
RepliesMemento::RepliesMemento(not_null<HistoryItem*> commentsItem)
|
||||
: RepliesMemento(commentsItem->history(), commentsItem->id) {
|
||||
if (const auto original = commentsItem->lookupDiscussionPostOriginal()) {
|
||||
RepliesMemento::RepliesMemento(
|
||||
not_null<HistoryItem*> commentsItem,
|
||||
MsgId commentId)
|
||||
: RepliesMemento(commentsItem->history(), commentsItem->id, commentId) {
|
||||
if (commentId) {
|
||||
_list.setAroundPosition({
|
||||
TimeId(0),
|
||||
FullMsgId(commentsItem->history()->channelId(), commentId)
|
||||
});
|
||||
} else if (const auto original = commentsItem->lookupDiscussionPostOriginal()) {
|
||||
if (original->commentsReadTill() == MsgId(1)) {
|
||||
_list.setAroundPosition(Data::MinMessagePosition);
|
||||
_list.setScrollTopState(ListMemento::ScrollTopState{
|
||||
|
@ -1085,8 +1092,12 @@ void RepliesWidget::showAtPosition(
|
|||
bool RepliesWidget::showAtPositionNow(
|
||||
Data::MessagePosition position,
|
||||
HistoryItem *originItem) {
|
||||
if (const auto scrollTop = _inner->scrollTopForPosition(position)) {
|
||||
while (_replyReturn && position.fullId.msg == _replyReturn->id) {
|
||||
const auto item = position.fullId
|
||||
? _history->owner().message(position.fullId)
|
||||
: nullptr;
|
||||
const auto use = item ? item->position() : position;
|
||||
if (const auto scrollTop = _inner->scrollTopForPosition(use)) {
|
||||
while (_replyReturn && use.fullId.msg == _replyReturn->id) {
|
||||
calculateNextReplyReturn();
|
||||
}
|
||||
const auto currentScrollTop = _scroll->scrollTop();
|
||||
|
@ -1096,14 +1107,14 @@ bool RepliesWidget::showAtPositionNow(
|
|||
const auto scrollDelta = snap(fullDelta, -limit, limit);
|
||||
_inner->animatedScrollTo(
|
||||
wanted,
|
||||
position,
|
||||
use,
|
||||
scrollDelta,
|
||||
(std::abs(fullDelta) > limit
|
||||
? HistoryView::ListWidget::AnimatedScroll::Part
|
||||
: HistoryView::ListWidget::AnimatedScroll::Full));
|
||||
if (position != Data::MaxMessagePosition
|
||||
&& position != Data::UnreadMessagePosition) {
|
||||
_inner->highlightMessage(position.fullId);
|
||||
if (use != Data::MaxMessagePosition
|
||||
&& use != Data::UnreadMessagePosition) {
|
||||
_inner->highlightMessage(use.fullId);
|
||||
}
|
||||
if (originItem) {
|
||||
pushReplyReturn(originItem);
|
||||
|
@ -1303,6 +1314,15 @@ void RepliesWidget::restoreState(not_null<RepliesMemento*> memento) {
|
|||
}
|
||||
restoreReplyReturns(memento->replyReturns());
|
||||
_inner->restoreState(memento->list());
|
||||
if (const auto highlight = memento->getHighlightId()) {
|
||||
const auto position = Data::MessagePosition{
|
||||
TimeId(0),
|
||||
FullMsgId(_history->channelId(), highlight)
|
||||
};
|
||||
_inner->showAroundPosition(position, [=] {
|
||||
return showAtPositionNow(position, nullptr);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RepliesWidget::resizeEvent(QResizeEvent *e) {
|
||||
|
|
|
@ -271,11 +271,17 @@ private:
|
|||
|
||||
class RepliesMemento : public Window::SectionMemento {
|
||||
public:
|
||||
RepliesMemento(not_null<History*> history, MsgId rootId)
|
||||
RepliesMemento(
|
||||
not_null<History*> history,
|
||||
MsgId rootId,
|
||||
MsgId highlightId = 0)
|
||||
: _history(history)
|
||||
, _rootId(rootId) {
|
||||
, _rootId(rootId)
|
||||
, _highlightId(highlightId) {
|
||||
}
|
||||
explicit RepliesMemento(not_null<HistoryItem*> commentsItem);
|
||||
explicit RepliesMemento(
|
||||
not_null<HistoryItem*> commentsItem,
|
||||
MsgId commentId = 0);
|
||||
|
||||
object_ptr<Window::SectionWidget> createWidget(
|
||||
QWidget *parent,
|
||||
|
@ -307,10 +313,14 @@ public:
|
|||
[[nodiscard]] not_null<ListMemento*> list() {
|
||||
return &_list;
|
||||
}
|
||||
[[nodiscard]] MsgId getHighlightId() const {
|
||||
return _highlightId;
|
||||
}
|
||||
|
||||
private:
|
||||
const not_null<History*> _history;
|
||||
const MsgId _rootId = 0;
|
||||
const MsgId _highlightId = 0;
|
||||
ListMemento _list;
|
||||
std::shared_ptr<Data::RepliesList> _replies;
|
||||
std::vector<MsgId> _replyReturns;
|
||||
|
|
|
@ -2597,101 +2597,25 @@ void MainWidget::searchInChat(Dialogs::Key chat) {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWidget::openPeerByName(
|
||||
const QString &username,
|
||||
void MainWidget::openPeerResolved(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId msgId,
|
||||
const QString &startToken,
|
||||
FullMsgId clickFromMessageId) {
|
||||
Core::App().hideMediaView();
|
||||
|
||||
if (const auto peer = session().data().peerByUsername(username)) {
|
||||
if (msgId == ShowAtGameShareMsgId) {
|
||||
if (peer->isUser() && peer->asUser()->isBot() && !startToken.isEmpty()) {
|
||||
peer->asUser()->botInfo->shareGameShortName = startToken;
|
||||
AddBotToGroupBoxController::Start(
|
||||
_controller,
|
||||
peer->asUser());
|
||||
} else {
|
||||
InvokeQueued(this, [this, peer] {
|
||||
_controller->showPeerHistory(
|
||||
peer->id,
|
||||
SectionShow::Way::Forward);
|
||||
});
|
||||
}
|
||||
} else if (msgId == ShowAtProfileMsgId && !peer->isChannel()) {
|
||||
if (peer->isUser() && peer->asUser()->isBot() && !peer->asUser()->botInfo->cantJoinGroups && !startToken.isEmpty()) {
|
||||
peer->asUser()->botInfo->startGroupToken = startToken;
|
||||
AddBotToGroupBoxController::Start(
|
||||
_controller,
|
||||
peer->asUser());
|
||||
} else if (peer->isUser() && peer->asUser()->isBot()) {
|
||||
// Always open bot chats, even from mention links.
|
||||
InvokeQueued(this, [this, peer] {
|
||||
_controller->showPeerHistory(
|
||||
peer->id,
|
||||
SectionShow::Way::Forward);
|
||||
});
|
||||
} else {
|
||||
_controller->showPeerInfo(peer);
|
||||
}
|
||||
if (msgId == ShowAtGameShareMsgId) {
|
||||
if (peer->isUser() && peer->asUser()->isBot() && !startToken.isEmpty()) {
|
||||
peer->asUser()->botInfo->shareGameShortName = startToken;
|
||||
AddBotToGroupBoxController::Start(
|
||||
_controller,
|
||||
peer->asUser());
|
||||
} else {
|
||||
if (msgId == ShowAtProfileMsgId || !peer->isChannel()) { // show specific posts only in channels / supergroups
|
||||
msgId = ShowAtUnreadMsgId;
|
||||
}
|
||||
if (peer->isUser() && peer->asUser()->isBot()) {
|
||||
peer->asUser()->botInfo->startToken = startToken;
|
||||
if (peer == _history->peer()) {
|
||||
_history->updateControlsVisibility();
|
||||
_history->updateControlsGeometry();
|
||||
}
|
||||
}
|
||||
const auto returnToId = clickFromMessageId;
|
||||
InvokeQueued(this, [=] {
|
||||
auto params = SectionShow{
|
||||
SectionShow::Way::Forward
|
||||
};
|
||||
params.origin = SectionShow::OriginMessage{
|
||||
returnToId
|
||||
};
|
||||
_controller->showPeerHistory(peer->id, params, msgId);
|
||||
InvokeQueued(this, [this, peer] {
|
||||
_controller->showPeerHistory(
|
||||
peer->id,
|
||||
SectionShow::Way::Forward);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
_api.request(MTPcontacts_ResolveUsername(
|
||||
MTP_string(username)
|
||||
)).done([=](const MTPcontacts_ResolvedPeer &result) {
|
||||
usernameResolveDone(result, msgId, startToken);
|
||||
}).fail([=](const RPCError &error) {
|
||||
usernameResolveFail(error, username);
|
||||
}).send();
|
||||
}
|
||||
}
|
||||
|
||||
bool MainWidget::contentOverlapped(const QRect &globalRect) {
|
||||
return (_history->contentOverlapped(globalRect)
|
||||
|| _playerPlaylist->overlaps(globalRect)
|
||||
|| (_playerVolume && _playerVolume->overlaps(globalRect)));
|
||||
}
|
||||
|
||||
void MainWidget::usernameResolveDone(
|
||||
const MTPcontacts_ResolvedPeer &result,
|
||||
MsgId msgId,
|
||||
const QString &startToken) {
|
||||
Ui::hideLayer();
|
||||
if (result.type() != mtpc_contacts_resolvedPeer) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &d(result.c_contacts_resolvedPeer());
|
||||
session().data().processUsers(d.vusers());
|
||||
session().data().processChats(d.vchats());
|
||||
const auto peerId = peerFromMTP(d.vpeer());
|
||||
if (!peerId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto peer = session().data().peer(peerId);
|
||||
if (msgId == ShowAtProfileMsgId && !peer->isChannel()) {
|
||||
} else if (msgId == ShowAtProfileMsgId && !peer->isChannel()) {
|
||||
if (peer->isUser() && peer->asUser()->isBot() && !peer->asUser()->botInfo->cantJoinGroups && !startToken.isEmpty()) {
|
||||
peer->asUser()->botInfo->startGroupToken = startToken;
|
||||
AddBotToGroupBoxController::Start(
|
||||
|
@ -2708,8 +2632,7 @@ void MainWidget::usernameResolveDone(
|
|||
_controller->showPeerInfo(peer);
|
||||
}
|
||||
} else {
|
||||
// show specific posts only in channels / supergroups
|
||||
if (msgId == ShowAtProfileMsgId || !peer->isChannel()) {
|
||||
if (msgId == ShowAtProfileMsgId || !peer->isChannel()) { // show specific posts only in channels / supergroups
|
||||
msgId = ShowAtUnreadMsgId;
|
||||
}
|
||||
if (peer->isUser() && peer->asUser()->isBot()) {
|
||||
|
@ -2720,19 +2643,88 @@ void MainWidget::usernameResolveDone(
|
|||
}
|
||||
}
|
||||
InvokeQueued(this, [=] {
|
||||
_controller->showPeerHistory(
|
||||
peer->id,
|
||||
SectionShow::Way::Forward,
|
||||
msgId);
|
||||
auto params = SectionShow{
|
||||
SectionShow::Way::Forward
|
||||
};
|
||||
params.origin = SectionShow::OriginMessage{
|
||||
clickFromMessageId
|
||||
};
|
||||
_controller->showPeerHistory(peer->id, params, msgId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::usernameResolveFail(const RPCError &error, const QString &username) {
|
||||
if (error.code() == 400) {
|
||||
Ui::show(Box<InformBox>(
|
||||
tr::lng_username_not_found(tr::now, lt_user, username)));
|
||||
void MainWidget::openPeerByName(
|
||||
const QString &username,
|
||||
MsgId msgId,
|
||||
const QString &startToken,
|
||||
FullMsgId clickFromMessageId) {
|
||||
Core::App().hideMediaView();
|
||||
resolveUsername(username, [=](not_null<PeerData*> peer) {
|
||||
openPeerResolved(peer, msgId, startToken, clickFromMessageId);
|
||||
});
|
||||
}
|
||||
|
||||
void MainWidget::openCommentByName(
|
||||
const QString &username,
|
||||
MsgId msgId,
|
||||
MsgId commentId,
|
||||
FullMsgId clickFromMessageId) {
|
||||
Core::App().hideMediaView();
|
||||
resolveUsername(username, [=](not_null<PeerData*> peer) {
|
||||
InvokeQueued(this, [=] {
|
||||
auto params = SectionShow{
|
||||
SectionShow::Way::Forward
|
||||
};
|
||||
params.origin = SectionShow::OriginMessage{
|
||||
clickFromMessageId
|
||||
};
|
||||
_controller->showRepliesForMessage(
|
||||
session().data().history(peer),
|
||||
msgId,
|
||||
commentId,
|
||||
params);
|
||||
});
|
||||
});
|
||||
Core::App().hideMediaView();
|
||||
}
|
||||
|
||||
bool MainWidget::contentOverlapped(const QRect &globalRect) {
|
||||
return (_history->contentOverlapped(globalRect)
|
||||
|| _playerPlaylist->overlaps(globalRect)
|
||||
|| (_playerVolume && _playerVolume->overlaps(globalRect)));
|
||||
}
|
||||
|
||||
void MainWidget::resolveUsername(
|
||||
const QString &username,
|
||||
Fn<void(not_null<PeerData*>)> done) {
|
||||
if (const auto peer = session().data().peerByUsername(username)) {
|
||||
done(peer);
|
||||
return;
|
||||
}
|
||||
_api.request(base::take(_resolveRequestId)).cancel();
|
||||
_resolveRequestId = _api.request(MTPcontacts_ResolveUsername(
|
||||
MTP_string(username)
|
||||
)).done([=](const MTPcontacts_ResolvedPeer &result) {
|
||||
_resolveRequestId = 0;
|
||||
Ui::hideLayer();
|
||||
if (result.type() != mtpc_contacts_resolvedPeer) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &d(result.c_contacts_resolvedPeer());
|
||||
session().data().processUsers(d.vusers());
|
||||
session().data().processChats(d.vchats());
|
||||
if (const auto peerId = peerFromMTP(d.vpeer())) {
|
||||
done(session().data().peer(peerId));
|
||||
}
|
||||
}).fail([=](const RPCError &error) {
|
||||
_resolveRequestId = 0;
|
||||
if (error.code() == 400) {
|
||||
Ui::show(Box<InformBox>(
|
||||
tr::lng_username_not_found(tr::now, lt_user, username)));
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
|
||||
void MainWidget::activate() {
|
||||
|
|
|
@ -127,6 +127,11 @@ public:
|
|||
MsgId msgId = ShowAtUnreadMsgId,
|
||||
const QString &startToken = QString(),
|
||||
FullMsgId clickFromMessageId = FullMsgId());
|
||||
void openCommentByName(
|
||||
const QString &name,
|
||||
MsgId msgId,
|
||||
MsgId commentId,
|
||||
FullMsgId clickFromMessageId = FullMsgId());
|
||||
|
||||
void activate();
|
||||
|
||||
|
@ -289,13 +294,14 @@ private:
|
|||
|
||||
void saveSectionInStack();
|
||||
|
||||
void usernameResolveDone(
|
||||
const MTPcontacts_ResolvedPeer &result,
|
||||
void resolveUsername(
|
||||
const QString &username,
|
||||
Fn<void(not_null<PeerData*>)> done);
|
||||
void openPeerResolved(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId msgId,
|
||||
const QString &startToken);
|
||||
void usernameResolveFail(
|
||||
const RPCError &error,
|
||||
const QString &username);
|
||||
const QString &startToken,
|
||||
FullMsgId clickFromMessageId);
|
||||
|
||||
int getMainSectionTop() const;
|
||||
int getThirdSectionTop() const;
|
||||
|
@ -400,6 +406,7 @@ private:
|
|||
base::flat_map<not_null<PeerData*>, mtpRequestId> _viewsIncrementRequests;
|
||||
base::flat_map<mtpRequestId, not_null<PeerData*>> _viewsIncrementByRequest;
|
||||
base::Timer _viewsIncrementTimer;
|
||||
mtpRequestId _resolveRequestId = 0;
|
||||
|
||||
struct SettingBackground;
|
||||
std::unique_ptr<SettingBackground> _background;
|
||||
|
|
|
@ -94,6 +94,7 @@ Main::Session &SessionNavigation::session() const {
|
|||
void SessionNavigation::showRepliesForMessage(
|
||||
not_null<History*> history,
|
||||
MsgId rootId,
|
||||
MsgId commentId,
|
||||
const SectionShow ¶ms) {
|
||||
if (_showingRepliesRequestId
|
||||
&& _showingRepliesHistory == history.get()
|
||||
|
@ -104,13 +105,13 @@ void SessionNavigation::showRepliesForMessage(
|
|||
|
||||
const auto channelId = history->channelId();
|
||||
const auto item = _session->data().message(channelId, rootId);
|
||||
if (!item || !item->repliesAreComments()) {
|
||||
if (!commentId && (!item || !item->repliesAreComments())) {
|
||||
showSection(HistoryView::RepliesMemento(history, rootId));
|
||||
return;
|
||||
} else if (const auto id = item->commentsItemId()) {
|
||||
if (const auto item = _session->data().message(id)) {
|
||||
} else if (const auto id = item ? item->commentsItemId() : FullMsgId()) {
|
||||
if (const auto commentsItem = _session->data().message(id)) {
|
||||
showSection(
|
||||
HistoryView::RepliesMemento(item));
|
||||
HistoryView::RepliesMemento(commentsItem));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +156,7 @@ void SessionNavigation::showRepliesForMessage(
|
|||
}
|
||||
}
|
||||
showSection(
|
||||
HistoryView::RepliesMemento(item));
|
||||
HistoryView::RepliesMemento(item, commentId));
|
||||
}
|
||||
});
|
||||
}).fail([=](const RPCError &error) {
|
||||
|
|
|
@ -141,6 +141,7 @@ public:
|
|||
void showRepliesForMessage(
|
||||
not_null<History*> history,
|
||||
MsgId rootId,
|
||||
MsgId commentId = 0,
|
||||
const SectionShow ¶ms = SectionShow());
|
||||
|
||||
void showPeerInfo(
|
||||
|
|
Loading…
Add table
Reference in a new issue