Merge tag 'v5.13.1' into dev

This commit is contained in:
AlexeyZavar
2025-04-25 02:03:14 +03:00
200 changed files with 6117 additions and 1350 deletions
+238 -88
View File
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "dialogs/dialogs_widget.h"
#include "base/call_delayed.h"
#include "base/qt/qt_key_modifiers.h"
#include "base/options.h"
#include "dialogs/ui/chat_search_in.h"
@@ -15,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "dialogs/ui/dialogs_suggestions.h"
#include "dialogs/dialogs_inner_widget.h"
#include "dialogs/dialogs_search_from_controllers.h"
#include "dialogs/dialogs_quick_action.h"
#include "dialogs/dialogs_key.h"
#include "history/history.h"
#include "history/history_item.h"
@@ -35,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/chat/more_chats_bar.h"
#include "ui/controls/download_bar.h"
#include "ui/controls/jump_down_button.h"
#include "ui/controls/swipe_handler.h"
#include "ui/painter.h"
#include "ui/rect.h"
#include "ui/ui_utility.h"
@@ -46,6 +49,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session_settings.h"
#include "api/api_chat_filters.h"
#include "apiwrap.h"
#include "chat_helpers/message_field.h"
#include "core/application.h"
#include "core/ui_integration.h"
#include "core/update_checker.h"
@@ -59,6 +63,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/storage_account.h"
#include "storage/storage_domain.h"
#include "data/components/recent_peers.h"
#include "data/components/sponsored_messages.h"
#include "data/data_session.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
@@ -366,6 +371,7 @@ Widget::Widget(
_storiesContents.events() | rpl::flatten_latest())
: nullptr)
, _searchTimer([=] { search(); })
, _peerSearch(&controller->session(), Api::PeerSearch::Type::WithSponsored)
, _singleMessageSearch(&controller->session()) {
const auto makeChildListShown = [](PeerId peerId, float64 shown) {
return InnerWidget::ChildListShown{ peerId, shown };
@@ -381,6 +387,10 @@ Widget::Widget(
_childListPeerId.value(),
_childListShown.value(),
makeChildListShown)));
_scroll->heightValue() | rpl::start_with_next([=](int height) {
_inner->setMinimumHeight(height);
_inner->refresh();
}, _inner->lifetime());
_scrollToTop->raise();
_lockUnlock->toggle(false, anim::type::instant);
@@ -671,18 +681,169 @@ Widget::Widget(
setupMoreChatsBar();
setupDownloadBar();
}
setupSwipeBack();
if (session().settings().dialogsFiltersEnabled()
&& (Core::App().settings().chatFiltersHorizontal()
|| !controller->enoughSpaceForFilters())) {
toggleFiltersMenu(true);
}
setupFrozenAccountBar();
}
void Widget::setupSwipeBack() {
const auto isMainList = [=] {
const auto current = controller()->activeChatsFilterCurrent();
const auto &chatsFilters = session().data().chatsFilters();
if (chatsFilters.has()) {
return chatsFilters.defaultId() == current;
}
return !current;
};
auto update = [=](Ui::Controls::SwipeContextData data) {
if (data.translation != 0) {
if (data.translation < 0
&& _inner
&& (Core::App().settings().quickDialogAction()
!= Ui::QuickDialogAction::Disabled)) {
_inner->setSwipeContextData(data.msgBareId, std::move(data));
} else {
if (!_swipeBackData.callback) {
_swipeBackData = Ui::Controls::SetupSwipeBack(
this,
[]() -> std::pair<QColor, QColor> {
return {
st::historyForwardChooseBg->c,
st::historyForwardChooseFg->c,
};
},
_swipeBackMirrored,
_swipeBackIconMirrored);
}
_swipeBackData.callback(data);
}
return;
} else {
if (_swipeBackData.lifetime) {
_swipeBackData = {};
}
if (_inner) {
_inner->setSwipeContextData(data.msgBareId, std::nullopt);
_inner->update();
}
}
};
auto init = [=](int top, Qt::LayoutDirection direction) {
_swipeBackIconMirrored = false;
_swipeBackMirrored = false;
if (_childListShown.current()) {
return Ui::Controls::SwipeHandlerFinishData();
}
const auto isRightToLeft = direction == Qt::RightToLeft;
const auto action = Core::App().settings().quickDialogAction();
const auto isDisabled = action == Ui::QuickDialogAction::Disabled;
if (_inner) {
_inner->clearQuickActions();
if (!isRightToLeft) {
if (const auto key = _inner->calcSwipeKey(top);
key && !isDisabled) {
_inner->prepareQuickAction(key, action);
return Ui::Controls::SwipeHandlerFinishData{
.callback = [=, session = &session()] {
auto callback = [=, peerId = PeerId(key)] {
PerformQuickDialogAction(
controller(),
session->data().peer(peerId),
action,
_inner->filterId());
};
base::call_delayed(
st::slideWrapDuration,
session,
std::move(callback));
},
.msgBareId = key,
.speedRatio = 1.,
.reachRatioDuration = crl::time(
st::slideWrapDuration),
.provideReachOutRatio = true,
};
}
}
}
if (controller()->openedFolder().current()) {
if (!isRightToLeft) {
return Ui::Controls::SwipeHandlerFinishData();
}
return Ui::Controls::DefaultSwipeBackHandlerFinishData([=] {
_swipeBackData = {};
if (controller()->openedFolder().current()) {
if (!controller()->windowId().folder()) {
controller()->closeFolder();
}
}
});
}
if (controller()->shownForum().current()) {
if (!isRightToLeft) {
return Ui::Controls::SwipeHandlerFinishData();
}
const auto id = controller()->windowId();
const auto initial = id.forum();
if (initial) {
return Ui::Controls::SwipeHandlerFinishData();
}
return Ui::Controls::DefaultSwipeBackHandlerFinishData([=] {
_swipeBackData = {};
if (const auto forum = controller()->shownForum().current()) {
controller()->closeForum();
}
});
}
if (isRightToLeft && isMainList()) {
_swipeBackIconMirrored = true;
return Ui::Controls::DefaultSwipeBackHandlerFinishData([=] {
_swipeBackIconMirrored = false;
_swipeBackData = {};
if (isMainList()) {
showMainMenu();
}
});
}
if (session().data().chatsFilters().has() && isDisabled) {
_swipeBackMirrored = !isRightToLeft;
using namespace Window;
const auto next = !isRightToLeft;
if (CheckAndJumpToNearChatsFilter(controller(), next, false)) {
return Ui::Controls::DefaultSwipeBackHandlerFinishData([=] {
_swipeBackData = {};
CheckAndJumpToNearChatsFilter(controller(), next, true);
});
}
}
return Ui::Controls::SwipeHandlerFinishData();
};
Ui::Controls::SetupSwipeHandler({
.widget = _inner,
.scroll = _scroll.data(),
.update = std::move(update),
.init = std::move(init),
});
}
void Widget::chosenRow(const ChosenRow &row) {
storiesToggleExplicitExpand(false);
if (!_searchState.query.isEmpty()) {
if (!row.sponsoredRandomId.isEmpty()) {
auto &messages = session().sponsoredMessages();
messages.clicked(row.sponsoredRandomId, false, false);
} else if (!_searchState.query.isEmpty()) {
if (const auto history = row.key.history()) {
session().recentPeers().bump(history->peer);
}
@@ -692,6 +853,7 @@ void Widget::chosenRow(const ChosenRow &row) {
const auto topicJump = history
? history->peer->forumTopicFor(row.message.fullId.msg)
: nullptr;
if (topicJump) {
if (controller()->shownForum().current() == topicJump->forum()) {
controller()->closeForum();
@@ -843,6 +1005,29 @@ void Widget::setupTouchChatPreview() {
}, _inner->lifetime());
}
void Widget::setupFrozenAccountBar() {
session().frozenValue(
) | rpl::start_with_next([=] {
updateFrozenAccountBar();
updateControlsGeometry();
}, lifetime());
}
void Widget::updateFrozenAccountBar() {
if (_layout == Layout::Child
|| _openedForum
|| _openedFolder
|| !session().frozen()) {
_frozenAccountBar = nullptr;
} else if (!_frozenAccountBar) {
_frozenAccountBar = FrozenWriteRestriction(
this,
controller()->uiShow(),
FrozenWriteRestrictionType::DialogsList);
_frozenAccountBar->show();
}
}
void Widget::setupMoreChatsBar() {
if (_layout == Layout::Child) {
return;
@@ -1220,6 +1405,14 @@ void Widget::setupShortcuts() {
}
return true;
});
request->check(Command::ShowChatPreview, 1)
&& request->handle([=] {
if (_inner) {
Window::ActivateWindow(controller());
return _inner->showChatPreview();
}
return true;
});
}
}, lifetime());
}
@@ -1258,6 +1451,9 @@ void Widget::updateControlsVisibility(bool fast) {
if (_moreChatsBar) {
_moreChatsBar->show();
}
if (_frozenAccountBar) {
_frozenAccountBar->show();
}
if (_chatFilters) {
_chatFilters->show();
}
@@ -1541,7 +1737,7 @@ void Widget::changeOpenedSubsection(
change();
refreshTopBars();
updateControlsVisibility(true);
_peerSearchRequest = 0;
_peerSearch.clear();
_api.request(base::take(_topicSearchRequest)).cancel();
if (animated == anim::type::normal) {
if (_connecting) {
@@ -1576,6 +1772,7 @@ void Widget::changeOpenedFolder(Data::Folder *folder, anim::type animated) {
if (_stories) {
storiesExplicitCollapse();
}
updateFrozenAccountBar();
}, (folder != nullptr), animated);
}
@@ -1632,6 +1829,7 @@ void Widget::changeOpenedForum(Data::Forum *forum, anim::type animated) {
_api.request(base::take(_topicSearchRequest)).cancel();
_inner->changeOpenedForum(forum);
storiesToggleExplicitExpand(false);
updateFrozenAccountBar();
updateStoriesVisibility();
}, (forum != nullptr), animated);
}
@@ -1963,6 +2161,9 @@ void Widget::startWidthAnimation() {
}
_widthAnimationCache = grabNonNarrowScrollFrame();
_scroll->hide();
if (_frozenAccountBar) {
_frozenAccountBar->hide();
}
if (_chatFilters) {
_chatFilters->hide();
}
@@ -1973,6 +2174,9 @@ void Widget::stopWidthAnimation() {
_widthAnimationCache = QPixmap();
if (!_showAnimation) {
_scroll->setVisible(!_suggestions);
if (_frozenAccountBar) {
_frozenAccountBar->setVisible(!_suggestions);
}
if (_chatFilters) {
_chatFilters->setVisible(!_suggestions);
}
@@ -2077,6 +2281,9 @@ void Widget::startSlideAnimation(
if (_moreChatsBar) {
_moreChatsBar->hide();
}
if (_frozenAccountBar) {
_frozenAccountBar->hide();
}
if (_chatFilters) {
_chatFilters->hide();
}
@@ -2241,10 +2448,9 @@ bool Widget::search(bool inCache, SearchRequestDelay delay) {
{ .posts = true, .start = true },
&_postsProcess);
}
_api.request(base::take(_peerSearchRequest)).cancel();
_peerSearchQuery = QString();
peerSearchApplyEmpty(0);
_peerSearch.clear();
_api.request(base::take(_topicSearchRequest)).cancel();
peerSearchReceived({});
return true;
} else if (inCache) {
const auto success = _singleMessageSearch.lookup(query, [=] {
@@ -2349,35 +2555,18 @@ bool Widget::search(bool inCache, SearchRequestDelay delay) {
} else {
_inner->searchRequested(false);
}
const auto peerQuery = Api::ConvertPeerSearchQuery(query);
if (searchForPeersRequired(peerQuery)) {
if (inCache) {
auto i = _peerSearchCache.find(peerQuery);
if (i != _peerSearchCache.end()) {
_peerSearchQuery = peerQuery;
_peerSearchRequest = 0;
peerSearchReceived(i->second, 0);
}
} else if (_peerSearchQuery != peerQuery) {
_peerSearchQuery = peerQuery;
_peerSearchFull = false;
_peerSearchRequest = _api.request(MTPcontacts_Search(
MTP_string(_peerSearchQuery),
MTP_int(SearchPeopleLimit)
)).done([=](
const MTPcontacts_Found &result,
mtpRequestId requestId) {
peerSearchReceived(result, requestId);
}).fail([=](const MTP::Error &error, mtpRequestId requestId) {
peerSearchFailed(error, requestId);
}).send();
_peerSearchQueries.emplace(_peerSearchRequest, _peerSearchQuery);
}
if (peerSearchRequired()) {
const auto requestType = inCache
? Api::PeerSearch::RequestType::CacheOnly
: Api::PeerSearch::RequestType::CacheOrRemote;
_peerSearch.request(query, [=](Api::PeerSearchResult result) {
peerSearchReceived(result);
}, requestType);
} else {
_api.request(base::take(_peerSearchRequest)).cancel();
_peerSearchQuery = peerQuery;
peerSearchApplyEmpty(0);
_peerSearch.clear();
peerSearchReceived({});
}
const auto peerQuery = Api::ConvertPeerSearchQuery(query);
if (searchForTopicsRequired(peerQuery)) {
if (inCache) {
if (_topicSearchQuery != peerQuery) {
@@ -2396,11 +2585,8 @@ bool Widget::search(bool inCache, SearchRequestDelay delay) {
return result;
}
bool Widget::searchForPeersRequired(const QString &query) const {
return _searchState.filterChatsList()
&& !_openedForum
&& !query.isEmpty()
&& (IsHashOrCashtagSearchQuery(query) == HashOrCashtag::None);
bool Widget::peerSearchRequired() const {
return _searchState.filterChatsList() && !_openedForum;
}
bool Widget::searchForTopicsRequired(const QString &query) const {
@@ -2800,31 +2986,10 @@ void Widget::searchReceived(
update();
}
void Widget::peerSearchReceived(
const MTPcontacts_Found &result,
mtpRequestId requestId) {
const auto state = _inner->state();
auto q = _peerSearchQuery;
if (state == WidgetState::Filtered) {
auto i = _peerSearchQueries.find(requestId);
if (i != _peerSearchQueries.end()) {
_peerSearchCache[i->second] = result;
_peerSearchQueries.erase(i);
}
}
if (_peerSearchRequest == requestId) {
switch (result.type()) {
case mtpc_contacts_found: {
auto &d = result.c_contacts_found();
session().data().processUsers(d.vusers());
session().data().processChats(d.vchats());
_inner->peerSearchReceived(q, d.vmy_results().v, d.vresults().v);
} break;
}
_peerSearchRequest = 0;
listScrollUpdated();
}
void Widget::peerSearchReceived(Api::PeerSearchResult result) {
_inner->peerSearchReceived(std::move(result));
listScrollUpdated();
update();
}
void Widget::searchApplyEmpty(
@@ -2840,17 +3005,6 @@ void Widget::searchApplyEmpty(
process);
}
void Widget::peerSearchApplyEmpty(mtpRequestId id) {
_peerSearchFull = true;
peerSearchReceived(
MTP_contacts_found(
MTP_vector<MTPPeer>(0),
MTP_vector<MTPPeer>(0),
MTP_vector<MTPChat>(0),
MTP_vector<MTPUser>(0)),
id);
}
void Widget::searchFailed(
SearchRequestType type,
const MTP::Error &error,
@@ -2863,13 +3017,6 @@ void Widget::searchFailed(
}
}
void Widget::peerSearchFailed(const MTP::Error &error, mtpRequestId id) {
if (_peerSearchRequest == id) {
_peerSearchRequest = 0;
_peerSearchFull = true;
}
}
void Widget::dragEnterEvent(QDragEnterEvent *e) {
using namespace Storage;
@@ -3294,12 +3441,7 @@ bool Widget::applySearchState(SearchState state) {
clearSearchCache(searchCleared);
}
if (state.query.isEmpty()) {
_peerSearchCache.clear();
const auto queries = base::take(_peerSearchQueries);
for (const auto &[requestId, query] : queries) {
_api.request(requestId).cancel();
}
_peerSearchQuery = QString();
_peerSearch.clear();
}
if (_searchState.query != currentSearchQuery()) {
@@ -3357,8 +3499,8 @@ void Widget::clearSearchCache(bool clearPosts) {
_topicSearchQuery = QString();
_topicSearchOffsetDate = 0;
_topicSearchOffsetId = _topicSearchOffsetTopicId = 0;
_api.request(base::take(_peerSearchRequest)).cancel();
_api.request(base::take(_topicSearchRequest)).cancel();
_peerSearch.clear();
cancelSearchRequest();
}
@@ -3660,9 +3802,17 @@ void Widget::updateControlsGeometry() {
if (_chatFilters) {
_chatFilters->resizeToWidth(barw);
}
if (_frozenAccountBar) {
_frozenAccountBar->resize(barw, _frozenAccountBar->height());
}
_updateScrollGeometryCached = [=] {
const auto moreChatsBarTop = expandedStoriesTop
const auto frozenBarTop = expandedStoriesTop
+ ((!_stories || _stories->isHidden()) ? 0 : _aboveScrollAdded);
if (_frozenAccountBar) {
_frozenAccountBar->move(0, frozenBarTop);
}
const auto moreChatsBarTop = frozenBarTop
+ (_frozenAccountBar ? _frozenAccountBar->height() : 0);
if (_moreChatsBar) {
_moreChatsBar->move(0, moreChatsBarTop);
}