Fix bot about text selection.

This commit is contained in:
John Preston 2023-03-08 15:32:10 +04:00
parent 9c74c04738
commit 3a0b912274
3 changed files with 76 additions and 57 deletions

View file

@ -485,7 +485,7 @@ HistoryInner::HistoryInner(
return (request.item->history() == _history) return (request.item->history() == _history)
&& _controller->widget()->isActive(); && _controller->widget()->isActive();
}) | rpl::start_with_next([=](PlayRequest &&request) { }) | rpl::start_with_next([=](PlayRequest &&request) {
if (const auto view = request.item->mainView()) { if (const auto view = viewByItem(request.item)) {
_emojiInteractions->play(std::move(request), view); _emojiInteractions->play(std::move(request), view);
} }
}, lifetime()); }, lifetime());
@ -533,17 +533,17 @@ HistoryInner::HistoryInner(
repaintItem(view); repaintItem(view);
}, lifetime()); }, lifetime());
session().data().viewLayoutChanged( session().data().viewLayoutChanged(
) | rpl::filter([](not_null<const Element*> view) { ) | rpl::filter([=](not_null<const Element*> view) {
return (view == view->data()->mainView()) && view->isUnderCursor(); return (view == viewByItem(view->data())) && view->isUnderCursor();
}) | rpl::start_with_next([this](not_null<const Element*> view) { }) | rpl::start_with_next([=](not_null<const Element*> view) {
mouseActionUpdate(); mouseActionUpdate();
}, lifetime()); }, lifetime());
session().data().itemDataChanges( session().data().itemDataChanges(
) | rpl::filter([=](not_null<HistoryItem*> item) { ) | rpl::start_with_next([=](not_null<HistoryItem*> item) {
return item->mainView() != nullptr; if (const auto view = viewByItem(item)) {
}) | rpl::start_with_next([=](not_null<HistoryItem*> item) { view->itemDataChanged();
item->mainView()->itemDataChanged(); }
}, lifetime()); }, lifetime());
session().changes().historyUpdates( session().changes().historyUpdates(
@ -595,7 +595,7 @@ void HistoryInner::reactionChosen(const ChosenReaction &reaction) {
item->toggleReaction(reaction.id, HistoryItem::ReactionSource::Selector); item->toggleReaction(reaction.id, HistoryItem::ReactionSource::Selector);
if (!ranges::contains(item->chosenReactions(), reaction.id)) { if (!ranges::contains(item->chosenReactions(), reaction.id)) {
return; return;
} else if (const auto view = item->mainView()) { } else if (const auto view = viewByItem(item)) {
if (const auto top = itemTop(view); top >= 0) { if (const auto top = itemTop(view); top >= 0) {
const auto geometry = reaction.localGeometry.isEmpty() const auto geometry = reaction.localGeometry.isEmpty()
? mapFromGlobal(reaction.globalGeometry) ? mapFromGlobal(reaction.globalGeometry)
@ -699,10 +699,9 @@ void HistoryInner::messagesReceivedDown(
} }
void HistoryInner::repaintItem(const HistoryItem *item) { void HistoryInner::repaintItem(const HistoryItem *item) {
if (!item) { if (const auto view = viewByItem(item)) {
return; repaintItem(view);
} }
repaintItem(item->mainView());
} }
void HistoryInner::repaintItem(const Element *view) { void HistoryInner::repaintItem(const Element *view) {
@ -1034,7 +1033,13 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
if (const auto view = _botAbout ? _botAbout->view() : nullptr) { if (const auto view = _botAbout ? _botAbout->view() : nullptr) {
if (clip.y() < _botAbout->top + _botAbout->height if (clip.y() < _botAbout->top + _botAbout->height
&& clip.y() + clip.height() > _botAbout->top) { && clip.y() + clip.height() > _botAbout->top) {
const auto top = _botAbout->top;
context.translate(0, -top);
context.selection = computeRenderSelection(&_selected, view);
p.translate(0, top);
view->draw(p, context); view->draw(p, context);
context.translate(0, top);
p.translate(0, -top);
} }
} else if (historyDisplayedEmpty) { } else if (historyDisplayedEmpty) {
paintEmpty(p, context.st, width(), height()); paintEmpty(p, context.st, width(), height());
@ -1594,7 +1599,10 @@ QPoint HistoryInner::mapPointToItem(QPoint p, const Element *view) const {
QPoint HistoryInner::mapPointToItem( QPoint HistoryInner::mapPointToItem(
QPoint p, QPoint p,
const HistoryItem *item) const { const HistoryItem *item) const {
return item ? mapPointToItem(p, item->mainView()) : QPoint(); if (const auto view = viewByItem(item)) {
return mapPointToItem(p, view);
}
return QPoint();
} }
void HistoryInner::mousePressEvent(QMouseEvent *e) { void HistoryInner::mousePressEvent(QMouseEvent *e) {
@ -1738,9 +1746,7 @@ std::unique_ptr<QMimeData> HistoryInner::prepareDrag() {
return nullptr; return nullptr;
} }
const auto mouseActionView = _mouseActionItem const auto mouseActionView = viewByItem(_mouseActionItem);
? _mouseActionItem->mainView()
: nullptr;
bool uponSelected = false; bool uponSelected = false;
if (mouseActionView) { if (mouseActionView) {
if (!_selected.empty() && _selected.cbegin()->second == FullSelection) { if (!_selected.empty() && _selected.cbegin()->second == FullSelection) {
@ -1791,7 +1797,7 @@ std::unique_ptr<QMimeData> HistoryInner::prepareDrag() {
} }
return mimeData; return mimeData;
} else if (_dragStateItem) { } else if (_dragStateItem) {
const auto view = _dragStateItem->mainView(); const auto view = viewByItem(_dragStateItem);
if (!view) { if (!view) {
return nullptr; return nullptr;
} }
@ -1879,7 +1885,7 @@ void HistoryInner::itemRemoved(not_null<const HistoryItem*> item) {
void HistoryInner::viewRemoved(not_null<const Element*> view) { void HistoryInner::viewRemoved(not_null<const Element*> view) {
const auto refresh = [&](auto &saved) { const auto refresh = [&](auto &saved) {
if (saved == view) { if (saved == view) {
const auto now = view->data()->mainView(); const auto now = viewByItem(view->data());
saved = (now && now != view) ? now : nullptr; saved = (now && now != view) ? now : nullptr;
} }
}; };
@ -1903,7 +1909,7 @@ void HistoryInner::mouseActionFinish(
&& !_pressWasInactive && !_pressWasInactive
&& inSelectionMode() && inSelectionMode()
&& button != Qt::RightButton) { && button != Qt::RightButton) {
if (const auto view = _mouseActionItem->mainView()) { if (const auto view = viewByItem(_mouseActionItem)) {
if (view->toggleSelectionByHandlerClick(activated)) { if (view->toggleSelectionByHandlerClick(activated)) {
activated = nullptr; activated = nullptr;
} }
@ -1983,7 +1989,7 @@ void HistoryInner::mouseActionFinish(
&& _selected.cbegin()->second != FullSelection && _selected.cbegin()->second != FullSelection
&& !hasCopyRestriction(_selected.cbegin()->first)) { && !hasCopyRestriction(_selected.cbegin()->first)) {
const auto [item, selection] = *_selected.cbegin(); const auto [item, selection] = *_selected.cbegin();
if (const auto view = item->mainView()) { if (const auto view = viewByItem(item)) {
TextUtilities::SetClipboardText( TextUtilities::SetClipboardText(
view->selectedText(selection), view->selectedText(selection),
QClipboard::Selection); QClipboard::Selection);
@ -2001,9 +2007,7 @@ void HistoryInner::mouseReleaseEvent(QMouseEvent *e) {
void HistoryInner::mouseDoubleClickEvent(QMouseEvent *e) { void HistoryInner::mouseDoubleClickEvent(QMouseEvent *e) {
mouseActionStart(e->globalPos(), e->button()); mouseActionStart(e->globalPos(), e->button());
const auto mouseActionView = _mouseActionItem const auto mouseActionView = viewByItem(_mouseActionItem);
? _mouseActionItem->mainView()
: nullptr;
if (_mouseSelectType == TextSelectType::Letters if (_mouseSelectType == TextSelectType::Letters
&& mouseActionView && mouseActionView
&& ((_mouseAction == MouseAction::Selecting && ((_mouseAction == MouseAction::Selecting
@ -2312,7 +2316,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
const auto itemId = item->fullId(); const auto itemId = item->fullId();
_menu->addAction(tr::lng_context_select_msg(tr::now), [=] { _menu->addAction(tr::lng_context_select_msg(tr::now), [=] {
if (const auto item = session->data().message(itemId)) { if (const auto item = session->data().message(itemId)) {
if (const auto view = item->mainView()) { if (const auto view = viewByItem(item)) {
if (asGroup) { if (asGroup) {
changeSelectionAsGroup(&_selected, item, SelectAction::Select); changeSelectionAsGroup(&_selected, item, SelectAction::Select);
} else { } else {
@ -2433,7 +2437,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
const auto canForward = item && item->allowsForward(); const auto canForward = item && item->allowsForward();
const auto canReport = item && item->suggestReport(); const auto canReport = item && item->suggestReport();
const auto canBlockSender = item && item->history()->peer->isRepliesChat(); const auto canBlockSender = item && item->history()->peer->isRepliesChat();
const auto view = item ? item->mainView() : nullptr; const auto view = viewByItem(item);
const auto actionText = link const auto actionText = link
? link->copyToClipboardContextItemText() ? link->copyToClipboardContextItemText()
: QString(); : QString();
@ -2832,7 +2836,7 @@ TextForMimeData HistoryInner::getSelectedText() const {
} }
if (selected.cbegin()->second != FullSelection) { if (selected.cbegin()->second != FullSelection) {
const auto [item, selection] = *selected.cbegin(); const auto [item, selection] = *selected.cbegin();
if (const auto view = item->mainView()) { if (const auto view = viewByItem(item)) {
return view->selectedText(selection); return view->selectedText(selection);
} }
return TextForMimeData(); return TextForMimeData();
@ -3547,11 +3551,14 @@ void HistoryInner::mouseActionUpdate() {
adjustCurrent(point.y()); adjustCurrent(point.y());
const auto reactionState = _reactionsManager->buttonTextState(point); const auto reactionState = _reactionsManager->buttonTextState(point);
const auto reactionItem = session().data().message(reactionState.itemId); const auto reactionItem = session().data().message(reactionState.itemId);
const auto reactionView = reactionItem const auto reactionView = viewByItem(reactionItem);
? reactionItem->mainView()
: nullptr;
const auto view = reactionView const auto view = reactionView
? reactionView ? reactionView
: (_botAbout
&& _botAbout->view()
&& point.y() >= _botAbout->top
&& point.y() < _botAbout->top + _botAbout->view()->height())
? _botAbout->view()
: (_curHistory && !_curHistory->isEmpty()) : (_curHistory && !_curHistory->isEmpty())
? _curHistory->blocks[_curBlock]->messages[_curItem].get() ? _curHistory->blocks[_curBlock]->messages[_curItem].get()
: nullptr; : nullptr;
@ -3588,7 +3595,7 @@ void HistoryInner::mouseActionUpdate() {
} }
_reactionsManager->updateButton({}); _reactionsManager->updateButton({});
} }
if (_mouseActionItem && !_mouseActionItem->mainView()) { if (_mouseActionItem && !viewByItem(_mouseActionItem)) {
mouseActionCancel(); mouseActionCancel();
} }
@ -3602,17 +3609,6 @@ void HistoryInner::mouseActionUpdate() {
if (overReaction) { if (overReaction) {
dragState = reactionState; dragState = reactionState;
lnkhost = reactionView; lnkhost = reactionView;
} else if (point.y() < _historyPaddingTop) {
if (const auto view = _botAbout ? _botAbout->view() : nullptr) {
StateRequest request;
if (base::IsAltPressed()) {
request.flags &= ~Ui::Text::StateRequest::Flag::LookupLink;
}
const auto relative = point - QPoint(0, _botAbout->top);
dragState = view->textState(relative, request);
_dragStateItem = session().data().message(dragState.itemId);
lnkhost = view;
}
} else if (item) { } else if (item) {
if (item != _mouseActionItem || (m - _dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) { if (item != _mouseActionItem || (m - _dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) {
if (_mouseAction == MouseAction::PrepareDrag) { if (_mouseAction == MouseAction::PrepareDrag) {
@ -3740,7 +3736,7 @@ void HistoryInner::mouseActionUpdate() {
} }
auto selState = TextSelection { qMin(second, _mouseTextSymbol), qMax(second, _mouseTextSymbol) }; auto selState = TextSelection { qMin(second, _mouseTextSymbol), qMax(second, _mouseTextSymbol) };
if (_mouseSelectType != TextSelectType::Letters) { if (_mouseSelectType != TextSelectType::Letters) {
if (const auto view = _mouseActionItem->mainView()) { if (const auto view = viewByItem(_mouseActionItem)) {
selState = view->adjustSelection(selState, _mouseSelectType); selState = view->adjustSelection(selState, _mouseSelectType);
} }
} }
@ -3755,7 +3751,7 @@ void HistoryInner::mouseActionUpdate() {
updateDragSelection(nullptr, nullptr, false); updateDragSelection(nullptr, nullptr, false);
} else { } else {
auto selectingDown = (itemTop(_mouseActionItem) < itemTop(item)) || (_mouseActionItem == item && _dragStartPosition.y() < m.y()); auto selectingDown = (itemTop(_mouseActionItem) < itemTop(item)) || (_mouseActionItem == item && _dragStartPosition.y() < m.y());
auto dragSelFrom = _mouseActionItem->mainView(); auto dragSelFrom = viewByItem(_mouseActionItem);
auto dragSelTo = view; auto dragSelTo = view;
// Maybe exclude dragSelFrom. // Maybe exclude dragSelFrom.
if (dragSelFrom->pointState(_dragStartPosition) == PointState::Outside) { if (dragSelFrom->pointState(_dragStartPosition) == PointState::Outside) {
@ -3821,7 +3817,7 @@ void HistoryInner::mouseActionUpdate() {
// Voice message seek support. // Voice message seek support.
if (const auto pressedItem = _dragStateItem) { if (const auto pressedItem = _dragStateItem) {
if (const auto pressedView = pressedItem->mainView()) { if (const auto pressedView = viewByItem(pressedItem)) {
if (pressedItem->history() == _history || pressedItem->history() == _migrated) { if (pressedItem->history() == _history || pressedItem->history() == _migrated) {
auto adjustedPoint = mapPointToItem(point, pressedView); auto adjustedPoint = mapPointToItem(point, pressedView);
pressedView->updatePressed(adjustedPoint); pressedView->updatePressed(adjustedPoint);
@ -3917,14 +3913,17 @@ void HistoryInner::setCanHaveFromUserpicsSponsored(bool value) {
_canHaveFromUserpicsSponsored = value; _canHaveFromUserpicsSponsored = value;
} }
auto HistoryInner::viewByItem(const HistoryItem *item) const -> Element* {
return !item
? nullptr
: (_botAbout && _botAbout->item() == item)
? _botAbout->view()
: item->mainView();
}
// -1 if should not be visible, -2 if bad history() // -1 if should not be visible, -2 if bad history()
int HistoryInner::itemTop(const HistoryItem *item) const { int HistoryInner::itemTop(const HistoryItem *item) const {
if (!item) { return item ? itemTop(viewByItem(item)) : -2;
return -2;
} else if (_botAbout && item == _botAbout->item()) {
return _botAbout->top;
}
return itemTop(item->mainView());
} }
int HistoryInner::itemTop(const Element *view) const { int HistoryInner::itemTop(const Element *view) const {
@ -4226,11 +4225,30 @@ void HistoryInner::applyDragSelection(
if (!toItems->empty() && toItems->cbegin()->second != FullSelection) { if (!toItems->empty() && toItems->cbegin()->second != FullSelection) {
toItems->clear(); toItems->clear();
} }
const auto botAboutView = _botAbout ? _botAbout->view() : nullptr;
if (_dragSelecting) { if (_dragSelecting) {
auto fromblock = _dragSelFrom->block()->indexInHistory(); auto fromblock = (_dragSelFrom != botAboutView)
auto fromitem = _dragSelFrom->indexInBlock(); ? _dragSelFrom->block()->indexInHistory()
auto toblock = _dragSelTo->block()->indexInHistory(); : _history->blocks.empty()
auto toitem = _dragSelTo->indexInBlock(); ? -1
: 0;
auto fromitem = (_dragSelFrom != botAboutView)
? _dragSelFrom->indexInBlock()
: (_history->blocks.empty()
|| _history->blocks[0]->messages.empty())
? -1
: 0;
auto toblock = (_dragSelTo != botAboutView)
? _dragSelTo->block()->indexInHistory()
: _history->blocks.empty()
? -1
: 0;
auto toitem = (_dragSelTo != botAboutView)
? _dragSelTo->indexInBlock()
: (_history->blocks.empty()
|| _history->blocks[0]->messages.empty())
? -1
: 0;
if (_migrated) { if (_migrated) {
if (_dragSelFrom->history() == _migrated) { if (_dragSelFrom->history() == _migrated) {
if (_dragSelTo->history() == _migrated) { if (_dragSelTo->history() == _migrated) {

View file

@ -185,8 +185,9 @@ public:
void setCanHaveFromUserpicsSponsored(bool value); void setCanHaveFromUserpicsSponsored(bool value);
// -1 if should not be visible, -2 if bad history() // -1 if should not be visible, -2 if bad history()
int itemTop(const HistoryItem *item) const; [[nodiscard]] int itemTop(const HistoryItem *item) const;
int itemTop(const Element *view) const; [[nodiscard]] int itemTop(const Element *view) const;
[[nodiscard]] Element *viewByItem(const HistoryItem *item) const;
// Returns (view, offset-from-top). // Returns (view, offset-from-top).
[[nodiscard]] std::pair<Element*, int> findViewForPinnedTracking( [[nodiscard]] std::pair<Element*, int> findViewForPinnedTracking(

View file

@ -1097,7 +1097,7 @@ void OverlayWidget::updateControls() {
} }
return dNow; return dNow;
}(); }();
_dateText = Ui::FormatDateTime(d); _dateText = d.isValid() ? Ui::FormatDateTime(d) : QString();
if (!_fromName.isEmpty()) { if (!_fromName.isEmpty()) {
_fromNameLabel.setText(st::mediaviewTextStyle, _fromName, Ui::NameTextOptions()); _fromNameLabel.setText(st::mediaviewTextStyle, _fromName, Ui::NameTextOptions());
_nameNav = QRect(st::mediaviewTextLeft, height() - st::mediaviewTextTop, qMin(_fromNameLabel.maxWidth(), width() / 3), st::mediaviewFont->height); _nameNav = QRect(st::mediaviewTextLeft, height() - st::mediaviewTextTop, qMin(_fromNameLabel.maxWidth(), width() / 3), st::mediaviewFont->height);