diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index 5afa45572..c7b1f3da4 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -87,6 +87,14 @@ dialogsTextPaletteArchiveActive: TextPalette(defaultTextPalette) { linkFg: dialogsTextFgActive; } +dialogsEmptyHeight: 160px; +dialogsEmptySkip: 2px; +dialogsEmptyLabel: FlatLabel(defaultFlatLabel) { + minWidth: 32px; + align: align(top); + textFg: windowSubTextFg; +} + dialogsMenuToggle: IconButton { width: 40px; height: 40px; diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index c1e30d385..7ee3a6ca1 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/shortcuts.h" #include "ui/widgets/buttons.h" #include "ui/widgets/popup_menu.h" +#include "ui/text/text_utilities.h" #include "ui/text_options.h" #include "ui/ui_utility.h" #include "data/data_drafts.h" @@ -115,8 +116,6 @@ InnerWidget::InnerWidget( , _pinnedShiftAnimation([=](crl::time now) { return pinnedShiftAnimationCallback(now); }) -, _addContactLnk(this, tr::lng_add_contact_button(tr::now)) -, _editFilterLnk(this, tr::lng_filters_context_edit(tr::now)) , _cancelSearchInChat(this, st::dialogsCancelSearchInPeer) , _cancelSearchFromUser(this, st::dialogsCancelSearchInPeer) { @@ -124,8 +123,6 @@ InnerWidget::InnerWidget( setAttribute(Qt::WA_OpaquePaintEvent, true); #endif // OS_MAC_OLD - _addContactLnk->addClickHandler([] { App::wnd()->onShowAddContact(); }); - _editFilterLnk->addClickHandler([=] { editOpenedFilter(); }); _cancelSearchInChat->setClickedCallback([=] { cancelSearchInChat(); }); _cancelSearchInChat->hide(); _cancelSearchFromUser->setClickedCallback([=] { @@ -146,6 +143,7 @@ InnerWidget::InnerWidget( session().data().contactsLoaded().changes( ) | rpl::start_with_next([=] { refresh(); + refreshEmptyLabel(); }, lifetime()); session().data().itemRemoved( @@ -188,7 +186,9 @@ InnerWidget::InnerWidget( setupOnlineStatusCheck(); - session().data().chatsListChanges( + rpl::merge( + session().data().chatsListChanges(), + session().data().chatsListLoadedEvents() ) | rpl::filter([=](Data::Folder *folder) { return (folder == _openedFolder); }) | rpl::start_with_next([=] { @@ -498,19 +498,6 @@ void InnerWidget::paintEvent(QPaintEvent *e) { } if (!otherStart) { p.fillRect(dialogsClip, st::dialogsBg); - p.setFont(st::noContactsFont); - p.setPen(st::noContactsColor); - const auto phrase = _filterId - ? (session().data().chatsList()->loaded() - ? tr::lng_no_chats_filter(tr::now) - : tr::lng_contacts_loading(tr::now)) - : session().data().contactsLoaded().current() - ? tr::lng_no_chats(tr::now) - : tr::lng_contacts_loading(tr::now); - p.drawText( - QRect(0, 0, fullWidth, st::noContactsHeight - (session().data().contactsLoaded().current() ? st::noContactsFont->height : 0)), - phrase, - style::al_center); } } else if (_state == WidgetState::Filtered) { if (!_hashtagResults.empty()) { @@ -1410,8 +1397,7 @@ void InnerWidget::setSearchedPressed(int pressed) { } void InnerWidget::resizeEvent(QResizeEvent *e) { - _addContactLnk->move((width() - _addContactLnk->width()) / 2, (st::noContactsHeight + st::noContactsFont->height) / 2); - _editFilterLnk->move((width() - _editFilterLnk->width()) / 2, (st::noContactsHeight + st::noContactsFont->height) / 2); + resizeEmptyLabel(); const auto widthForCancelButton = qMax(width(), st::columnMinimalWidthLeft); const auto left = widthForCancelButton - st::dialogsSearchInSkip - _cancelSearchInChat->width(); const auto top = (st::dialogsSearchInHeight - st::dialogsCancelSearchInPeer.height) / 2; @@ -2200,19 +2186,12 @@ void InnerWidget::refresh(bool toTop) { if (needCollapsedRowsRefresh()) { return refreshWithCollapsedRows(toTop); } + refreshEmptyLabel(); const auto list = shownDialogs(); - _addContactLnk->setVisible(!_filterId - && (_state == WidgetState::Default) - && list->empty() - && session().data().contactsLoaded().current()); - _editFilterLnk->setVisible((_filterId > 0) - && (_state == WidgetState::Default) - && list->empty() - && session().data().chatsList()->loaded()); auto h = 0; if (_state == WidgetState::Default) { if (list->empty()) { - h = st::noContactsHeight; + h = st::dialogsEmptyHeight; } else { h = dialogsOffset() + list->size() * st::dialogsRowHeight; } @@ -2235,6 +2214,69 @@ void InnerWidget::refresh(bool toTop) { update(); } +void InnerWidget::refreshEmptyLabel() { + const auto data = &session().data(); + const auto state = !shownDialogs()->empty() + ? EmptyState::None + : (!_filterId && data->contactsLoaded().current()) + ? EmptyState::NoContacts + : (_filterId > 0) && data->chatsList()->loaded() + ? EmptyState::EmptyFolder + : EmptyState::Loading; + if (state == EmptyState::None) { + _emptyState = state; + _empty.destroy(); + return; + } else if (_emptyState == state) { + _empty->setVisible(_state == WidgetState::Default); + return; + } + _emptyState = state; + auto phrase = (state == EmptyState::NoContacts) + ? tr::lng_no_chats() + : (state == EmptyState::EmptyFolder) + ? tr::lng_no_chats_filter() + : tr::lng_contacts_loading(); + auto link = (state == EmptyState::NoContacts) + ? tr::lng_add_contact_button() + : (state == EmptyState::EmptyFolder) + ? tr::lng_filters_context_edit() + : rpl::single(QString()); + auto full = rpl::combine( + std::move(phrase), + std::move(link) + ) | rpl::map([](const QString &phrase, const QString &link) { + auto result = Ui::Text::WithEntities(phrase); + if (!link.isEmpty()) { + result.append("\n\n").append(Ui::Text::Link(link)); + } + return result; + }); + _empty.create(this, std::move(full), st::dialogsEmptyLabel); + resizeEmptyLabel(); + _empty->setClickHandlerFilter([=](const auto &...) { + if (_emptyState == EmptyState::NoContacts) { + App::wnd()->onShowAddContact(); + } else if (_emptyState == EmptyState::EmptyFolder) { + editOpenedFilter(); + } + return false; + }); + _empty->setVisible(_state == WidgetState::Default); +} + +void InnerWidget::resizeEmptyLabel() { + if (!_empty) { + return; + } + const auto useWidth = std::min( + _empty->naturalWidth(), + width() - 2 * st::dialogsEmptySkip); + const auto left = (width() - useWidth) / 2; + _empty->resizeToWidth(useWidth); + _empty->move(left, (st::dialogsEmptyHeight - _empty->height()) / 2); +} + void InnerWidget::clearMouseSelection(bool clearSelection) { _mouseSelection = false; _lastMousePosition = std::nullopt; @@ -2580,6 +2622,7 @@ void InnerWidget::switchToFilter(FilterId filterId) { _filterId = filterId; refreshWithCollapsedRows(true); } + refreshEmptyLabel(); } bool InnerWidget::chooseHashtag() { diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index 0669ecee5..f46265770 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -22,7 +22,7 @@ class Session; namespace Ui { class IconButton; class PopupMenu; -class LinkButton; +class FlatLabel; } // namespace Ui namespace Window { @@ -97,6 +97,8 @@ public: void clearFilter(); void refresh(bool toTop = false); + void refreshEmptyLabel(); + void resizeEmptyLabel(); bool chooseRow(); @@ -168,6 +170,13 @@ private: NextOrOriginal, }; + enum class EmptyState : uchar { + None, + Loading, + NoContacts, + EmptyFolder, + }; + Main::Session &session() const; void dialogRowReplaced(Row *oldRow, Row *newRow); @@ -357,6 +366,7 @@ private: int _filteredPressed = -1; bool _waitingForSearch = false; + EmptyState _emptyState = EmptyState::None; QString _peerSearchQuery; std::vector> _peerSearchResults; @@ -376,8 +386,7 @@ private: WidgetState _state = WidgetState::Default; - object_ptr _addContactLnk; - object_ptr _editFilterLnk; + object_ptr _empty = { nullptr }; object_ptr _cancelSearchInChat; object_ptr _cancelSearchFromUser; diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 86cb882aa..14c5da49f 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 86cb882aab071c2a7933fcfc8d0834e38dca3651 +Subproject commit 14c5da49f9e9c8a3495fb2f270ce94e7b9073ef5