Show loading placeholders in chats list.

This commit is contained in:
John Preston 2024-05-21 13:58:37 +04:00
parent e00c6ecfb8
commit 1865fd382c
5 changed files with 72 additions and 19 deletions

View file

@ -64,6 +64,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_controller.h"
#include "window/window_session_controller.h"
#include "window/window_peer_menu.h"
#include "ui/effects/loading_element.h"
#include "ui/widgets/multi_select.h"
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
#include "ui/empty_userpic.h"
@ -936,7 +937,17 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
}
const auto showUnreadInSearchResults = uniqueSearchResults();
if (!_searchResults.empty()) {
if (_searchResults.empty()) {
if (_loadingAnimation) {
const auto text = tr::lng_contacts_loading(tr::now);
p.fillRect(0, 0, fullWidth, st::searchedBarHeight, st::searchedBarBg);
p.setFont(st::searchedBarFont);
p.setPen(st::searchedBarFg);
p.drawTextLeft(st::searchedBarPosition.x(), st::searchedBarPosition.y(), width(), text);
p.translate(0, st::searchedBarHeight);
top += st::searchedBarHeight;
}
} else {
const auto text = showUnreadInSearchResults
? u"Search results"_q
: tr::lng_search_found_results(
@ -1442,7 +1453,7 @@ void InnerWidget::selectByMouse(QPoint globalPosition) {
updateSelectedRow();
}
}
if (!_waitingForSearch && !_searchResults.empty()) {
if (!_searchResults.empty()) {
auto skip = searchedOffset();
auto searchedSelected = (mouseY >= skip) ? ((mouseY - skip) / _st->height) : -1;
if (searchedSelected < 0 || searchedSelected >= _searchResults.size()) {
@ -2602,7 +2613,6 @@ void InnerWidget::applySearchState(SearchState state) {
clearFilter();
} else {
setState(WidgetState::Filtered);
_waitingForSearch = true;
_filterResults.clear();
_filterResultsGlobal.clear();
const auto append = [&](not_null<IndexedList*> list) {
@ -2986,13 +2996,6 @@ void InnerWidget::searchReceived(
} else {
_searchedCount = fullCount;
}
if (_waitingForSearch
&& (!_searchResults.empty()
|| !_searchInMigrated
|| type == SearchRequestType::MigratedFromStart
|| type == SearchRequestType::MigratedFromOffset)) {
_waitingForSearch = false;
}
refresh();
}
@ -3090,8 +3093,8 @@ void InnerWidget::refresh(bool toTop) {
h = searchedOffset() + st::recentPeersEmptyHeightMin;
_searchEmpty->setMinimalHeight(st::recentPeersEmptyHeightMin);
_searchEmpty->move(0, h - st::recentPeersEmptyHeightMin);
} else if (_waitingForSearch) {
h = searchedOffset() + (_searchResults.size() * _st->height) + ((_searchResults.empty() && !_searchState.inChat) ? -st::searchedBarHeight : 0);
} else if (_loadingAnimation) {
h = searchedOffset() + _loadingAnimation->height();
} else {
h = searchedOffset() + (_searchResults.size() * _st->height);
}
@ -3127,8 +3130,21 @@ void InnerWidget::refreshEmpty() {
} else if (_searchEmpty) {
_searchEmpty->show();
}
if (!_searchLoading || !empty) {
_loadingAnimation.destroy();
} else if (!_loadingAnimation) {
_loadingAnimation = Ui::CreateLoadingDialogRowWidget(
this,
*_st,
2);
_loadingAnimation->resizeToWidth(width());
_loadingAnimation->move(0, searchedOffset());
_loadingAnimation->show();
}
} else {
_searchEmpty.destroy();
_loadingAnimation.destroy();
}
const auto data = &session().data();
@ -3207,6 +3223,10 @@ void InnerWidget::resizeEmpty() {
_searchEmpty->resizeToWidth(width());
_searchEmpty->move(0, searchedOffset());
}
if (_loadingAnimation) {
_loadingAnimation->resizeToWidth(width());
_loadingAnimation->move(0, searchedOffset());
}
}
void InnerWidget::clearMouseSelection(bool clearSelection) {
@ -3269,7 +3289,6 @@ void InnerWidget::clearFilter() {
if (_state == WidgetState::Filtered || _searchState.inChat) {
if (_searchState.inChat) {
setState(WidgetState::Filtered);
_waitingForSearch = true;
} else {
setState(WidgetState::Default);
}

View file

@ -141,9 +141,6 @@ public:
[[nodiscard]] not_null<const style::DialogRow*> st() const {
return _st;
}
[[nodiscard]] bool waitingForSearch() const {
return _waitingForSearch;
}
[[nodiscard]] bool hasFilteredResults() const;
void applySearchState(SearchState state);
@ -467,7 +464,6 @@ private:
int _filteredSelected = -1;
int _filteredPressed = -1;
bool _waitingForSearch = false;
EmptyState _emptyState = EmptyState::None;
QString _peerSearchQuery;
@ -485,6 +481,7 @@ private:
WidgetState _state = WidgetState::Default;
object_ptr<Ui::RpWidget> _loadingAnimation = { nullptr };
object_ptr<SearchEmpty> _searchEmpty = { nullptr };
SearchState _searchEmptyState;
object_ptr<Ui::FlatLabel> _empty = { nullptr };

View file

@ -448,7 +448,7 @@ Widget::Widget(
_inner->setLoadMoreCallback([=] {
const auto state = _inner->state();
if (state == WidgetState::Filtered
&& (!_inner->waitingForSearch()
&& (!_searchFull
|| (_searchInMigrated
&& _searchFull
&& !_searchFullMigrated))) {
@ -1936,7 +1936,7 @@ void Widget::submit() {
const auto state = _inner->state();
if (state == WidgetState::Default
|| (state == WidgetState::Filtered
&& (!_inner->waitingForSearch() || _inner->hasFilteredResults()))) {
&& _inner->hasFilteredResults())) {
_inner->selectSkip(1);
_inner->chooseRow();
} else {

View file

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/rect.h"
#include "ui/rp_widget.h"
#include "styles/style_basic.h"
#include "styles/style_dialogs.h"
#include "styles/style_widgets.h"
namespace Ui {
@ -63,10 +64,28 @@ void LoadingText::paint(QPainter &p, int width) {
h / 2);
}
[[nodiscard]] const style::PeerListItem &PeerListItemFromDialogRow(
rpl::lifetime &lifetime,
const style::DialogRow &st) {
using namespace style;
const auto item = lifetime.make_state<PeerListItem>(PeerListItem{
.height = st.height,
.photoPosition = QPoint(st.padding.left(), st.padding.top()),
.namePosition = QPoint(st.nameLeft, st.nameTop),
.nameStyle = st::semiboldTextStyle,
.statusPosition = QPoint(st.textLeft, st.textTop),
.photoSize = st.photoSize,
});
return *item;
}
class LoadingPeerListItem final : public LoadingElement {
public:
LoadingPeerListItem(const style::PeerListItem &st) : _st(st) {
}
LoadingPeerListItem(const style::DialogRow &st)
: _st(PeerListItemFromDialogRow(_lifetime, st)) {
}
[[nodiscard]] int height() const override {
return _st.height;
@ -114,6 +133,7 @@ public:
}
private:
rpl::lifetime _lifetime;
const style::PeerListItem &_st;
};
@ -220,4 +240,15 @@ object_ptr<Ui::RpWidget> CreateLoadingPeerListItemWidget(
st);
}
object_ptr<Ui::RpWidget> CreateLoadingDialogRowWidget(
not_null<Ui::RpWidget*> parent,
const style::DialogRow &st,
int lines) {
return CreateLoadingElementWidget<LoadingPeerListItem>(
parent,
lines,
rpl::single(false),
st);
}
} // namespace Ui

View file

@ -13,6 +13,7 @@ class object_ptr;
namespace style {
struct FlatLabel;
struct PeerListItem;
struct DialogRow;
} // namespace style
namespace Ui {
@ -30,4 +31,9 @@ object_ptr<Ui::RpWidget> CreateLoadingPeerListItemWidget(
const style::PeerListItem &st,
int lines);
object_ptr<Ui::RpWidget> CreateLoadingDialogRowWidget(
not_null<Ui::RpWidget*> parent,
const style::DialogRow &st,
int lines);
} // namespace Ui