[chat] Fix parity gaps found by legacy chat view audit.

This commit is contained in:
John Preston
2026-07-04 00:20:21 +04:00
parent 2ab3f95046
commit 93dfa63097
6 changed files with 143 additions and 8 deletions

View File

@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/view/history_view_chat_section.h"
#include "history/admin_log/history_admin_log_section.h"
#include "history/view/controls/history_view_top_controls.h"
#include "history/view/controls/history_view_bottom_controls.h"
#include "history/view/controls/history_view_compose_controls.h"
@@ -188,6 +189,18 @@ constexpr auto kPsaAboutPrefix = "cloud_lng_about_psa_";
|| (id == ShowForChooseMessagesMsgId);
}
[[nodiscard]] FullMsgId ResolveHighlightId(
not_null<History*> history,
MsgId highlightId) {
if (highlightId < 0) {
const auto migrated = history->migrateFrom();
if (migrated && IsServerMsgId(-highlightId)) {
return FullMsgId(migrated->peer->id, -highlightId);
}
}
return FullMsgId(history->peer->id, highlightId);
}
} // namespace
ChatMemento::ChatMemento(
@@ -206,7 +219,7 @@ ChatMemento::ChatMemento(
_list.setAroundPosition(Data::MaxMessagePosition);
} else if (_highlightId || _id.sublist) {
_list.setAroundPosition({
.fullId = FullMsgId(_id.history->peer->id, _highlightId),
.fullId = ResolveHighlightId(_id.history, _highlightId),
.date = TimeId(0),
});
}
@@ -412,7 +425,13 @@ ChatWidget::ChatWidget(
) | rpl::map([=] {
return session().scheduledMessages().hasFor(_topic);
}) | rpl::type_erased
: rpl::single(false),
: (_repliesRootId || _sublist)
? (rpl::single(false) | rpl::type_erased)
: rpl::single(rpl::empty_value()) | rpl::then(
session().scheduledMessages().updates(_history)
) | rpl::map([=] {
return session().scheduledMessages().count(_history) > 0;
}) | rpl::type_erased,
.currentSuggest = [=] { return suggestOptions(); },
.processShortcut = [=](QString shortcut) {
const auto messages = &_peer->owner().shortcutMessages();
@@ -905,6 +924,33 @@ ChatWidget::ChatWidget(
}
}, lifetime());
if ((mode() == Mode::History) && !_topic) {
session().data().sentToScheduled(
) | rpl::filter([=](const Data::SentToScheduled &value) {
return (value.history == _history);
}) | rpl::on_next([=](const Data::SentToScheduled &value) {
const auto id = value.scheduledId;
crl::on_main(this, [=] {
controller->showSection(
std::make_shared<HistoryView::ScheduledMemento>(
_history,
id));
});
}, lifetime());
session().data().sentFromScheduled(
) | rpl::on_next([=](const Data::SentFromScheduled &value) {
if (value.item->awaitingVideoProcessing()
&& !_sentFromScheduledTip
&& HistoryView::ShowScheduledVideoPublished(
controller,
value,
crl::guard(this, [=] { _sentFromScheduledTip = false; }))) {
_sentFromScheduledTip = true;
}
}, lifetime());
}
if (mode() == Mode::History) {
using HistoryUpdateFlag = Data::HistoryUpdate::Flag;
session().changes().historyUpdates(
@@ -1721,6 +1767,9 @@ void ChatWidget::setupSwipeReplyAndBack() {
return result;
}
if (data.direction == Qt::RightToLeft) {
if (_inner->hasVisibleSimilarChannels()) {
return result;
}
return Ui::Controls::DefaultSwipeBackHandlerFinishData([=] {
controller()->showBackFromStack();
});
@@ -1733,6 +1782,7 @@ void ChatWidget::setupSwipeReplyAndBack() {
|| (!view->data()->isRegular()
&& (!view->data()->isEphemeral()
|| view->data()->out()))
|| view->data()->showSimilarChannels()
|| view->data()->isService()) {
return result;
}
@@ -3922,6 +3972,13 @@ void ChatWidget::subscribeToSublist() {
void ChatWidget::unreadCountUpdated() {
if (mode() == Mode::History) {
const auto migrated = _history->migrateFrom();
if (_history->unreadMark() || (migrated && migrated->unreadMark())) {
crl::on_main(this, [=] {
closeCurrent();
});
return;
}
const auto hideCounter = _history->isForum()
|| !_history->trackUnreadMessages();
refreshUnreadCountBadge(hideCounter
@@ -3984,7 +4041,7 @@ void ChatWidget::restoreState(not_null<ChatMemento*> memento) {
anim::type::instant);
params.highlight = memento->highlight();
showAtPosition(Data::MessagePosition{
.fullId = FullMsgId(_peer->id, highlight),
.fullId = ResolveHighlightId(_history, highlight),
.date = TimeId(0),
}, memento->originId(), params);
}
@@ -4313,6 +4370,8 @@ void ChatWidget::showFinishedHook() {
_topic->saveMeAsActiveSubsectionThread();
} else if (_sublist) {
_sublist->saveMeAsActiveSubsectionThread();
} else if (mode() == Mode::History) {
_history->saveMeAsActiveSubsectionThread();
}
updateControlsVisibility();
@@ -5722,6 +5781,18 @@ void ChatWidget::setupShortcuts() {
_history));
return true;
});
if (mode() == Mode::History) {
const auto channel = _peer->asChannel();
const auto hasRecentActions = channel
&& (channel->hasAdminRights() || channel->amCreator());
if (hasRecentActions) {
request->check(Command::ShowAdminLog, 1) && request->handle([=] {
controller()->showSection(
std::make_shared<AdminLog::SectionMemento>(channel));
return true;
});
}
}
if ((mode() == Mode::History) && session().supportMode()) {
request->check(Command::SupportToggleMuted)
&& request->handle([=] {

View File

@@ -609,6 +609,7 @@ private:
bool _loaded = false;
bool _maybeSendStart = false;
bool _sentFromScheduledTip = false;
History *_supportPreloadHistory = nullptr;
int _supportPreloadRequest = 0;

View File

@@ -929,7 +929,18 @@ bool AddEditMessageAction(
if (!HasEditMessageAction(request, list)) {
return false;
}
const auto item = request.item;
const auto item = [&]() -> HistoryItem* {
const auto base = request.item;
const auto view = base->groupId() ? request.view : nullptr;
if (!view) {
return base;
} else if (const auto quoteItem = request.quote.item) {
return quoteItem;
} else if (const auto textItem = view->textItem()) {
return textItem;
}
return base;
}();
if (!item->allowsEdit(base::unixtime::now())) {
return false;
}

View File

@@ -2030,6 +2030,24 @@ bool ListWidget::canConsumeHorizontalScroll(QPoint position, int delta) const {
delta);
}
bool ListWidget::hasVisibleSimilarChannels() const {
const auto from = std::lower_bound(
begin(_items),
end(_items),
_visibleTop,
[this](auto &elem, int top) {
return this->itemTop(elem) + elem->height() <= top;
});
for (auto i = from; i != end(_items); ++i) {
if (itemTop(*i) >= _visibleBottom) {
break;
} else if ((*i)->data()->showSimilarChannels()) {
return true;
}
}
return false;
}
bool ListWidget::consumeScrollAction(
QPoint delta,
Qt::ScrollPhase phase,
@@ -3257,9 +3275,16 @@ SelectedItems ListWidget::getSelectedItems() const {
TextSelection ListWidget::getSelectedTextRange(
not_null<HistoryItem*> item) const {
return (_selectedTextItem == item)
? _selectedTextSelection.flatRangeForEdit()
: TextSelection();
if (!hasSelectedText()) {
return TextSelection();
} else if (_selectedTextItem == item) {
return _selectedTextSelection.flatRangeForEdit();
} else if (const auto view = viewForItem(_selectedTextItem)) {
if (view->textItem() == item) {
return _selectedTextSelection.flatRangeForEdit();
}
}
return TextSelection();
}
MessageSelection ListWidget::getSelectedTextSelection(
@@ -5045,6 +5070,9 @@ void ListWidget::performDrag() {
if (_reactionsManager) {
_reactionsManager->updateButton({});
}
if (_replyButtonManager) {
_replyButtonManager->updateButton({});
}
_delegate->listLaunchDrag(
std::move(mimeData),
crl::guard(this, [=] { mouseActionUpdate(QCursor::pos()); }));
@@ -5466,6 +5494,9 @@ auto ListWidget::replyToMessageRequested() const
void ListWidget::replyToMessageRequestNotify(
FullReplyTo to,
bool forceAnotherChat) {
if (!to.quote.empty()) {
clearTextSelection();
}
_requestedToReplyToMessage.fire({ std::move(to), forceAnotherChat });
}

View File

@@ -414,6 +414,7 @@ public:
[[nodiscard]] bool canConsumeHorizontalScroll(
QPoint position,
int delta) const;
[[nodiscard]] bool hasVisibleSimilarChannels() const;
bool consumeScrollAction(
QPoint delta,
Qt::ScrollPhase phase,

View File

@@ -1527,6 +1527,15 @@ void MainWidget::showHistory(
}
}
}
const auto wasActivePeer = _controller->activeChatCurrent().peer();
if (wasActivePeer
&& (wasActivePeer != history->peer)
&& (way != Way::Forward)) {
ClearBotStartToken(wasActivePeer);
}
if (wasActivePeer != history->peer) {
session().api().views().removeIncremented(history->peer);
}
auto memento = std::make_shared<ChatMemento>(
ChatViewId{ .history = history },
showAtMsgId,
@@ -1543,6 +1552,14 @@ void MainWidget::showHistory(
auto showParams = params;
showParams.way = way;
showSection(std::move(memento), showParams);
if (_dialogs && !_dialogs->isHidden()) {
if (way != Way::Backward) {
_dialogs->scrollToEntry(Dialogs::RowDescriptor(
history,
FullMsgId(history->peer->id, showAtMsgId)));
}
_dialogs->update();
}
return;
}
@@ -2348,7 +2365,10 @@ bool MainWidget::showBackFromStack(const SectionShow &params) {
auto item = std::move(_stack.back());
_stack.pop_back();
if (const auto currentHistoryPeer = _history->peer()) {
const auto currentHistoryPeer = _history->peer()
? _history->peer()
: _controller->activeChatCurrent().peer();
if (currentHistoryPeer) {
ClearBotStartToken(currentHistoryPeer);
}
_thirdSectionFromStack = item->takeThirdSectionMemento();