diff --git a/Telegram/Resources/animations/no_chats.tgs b/Telegram/Resources/animations/no_chats.tgs new file mode 100644 index 0000000000..a30673b48a Binary files /dev/null and b/Telegram/Resources/animations/no_chats.tgs differ diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index d8566d25f5..cfeb51a1eb 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -434,6 +434,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_dlg_new_channel_name" = "Channel name"; "lng_dlg_new_bot_name" = "Bot name"; "lng_no_chats" = "Your chats will be here"; +"lng_no_conversations" = "You have no\nconversations yet."; +"lng_no_conversations_button" = "New Message"; +"lng_no_conversations_subtitle" = "Your contacts on Telegram"; "lng_no_chats_filter" = "No chats currently belong to this folder."; "lng_no_saved_sublists" = "You can save messages from other chats here."; "lng_contacts_loading" = "Loading..."; diff --git a/Telegram/Resources/qrc/telegram/animations.qrc b/Telegram/Resources/qrc/telegram/animations.qrc index 9beaa522d3..cc9c2313ed 100644 --- a/Telegram/Resources/qrc/telegram/animations.qrc +++ b/Telegram/Resources/qrc/telegram/animations.qrc @@ -38,6 +38,7 @@ ../../animations/edit_peers/topics_tabs.tgs ../../animations/edit_peers/topics_list.tgs ../../animations/edit_peers/direct_messages.tgs + ../../animations/no_chats.tgs ../../animations/dice/dice_idle.tgs ../../animations/dice/dart_idle.tgs diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index babbf4027a..b3e2eceea0 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -244,6 +244,17 @@ dialogsEmptyLabel: FlatLabel(defaultFlatLabel) { align: align(top); textFg: windowSubTextFg; } +dialogEmptyButton: RoundButton(defaultActiveButton) { +} +dialogEmptyButtonSkip: 12px; +dialogEmptyButtonLabel: FlatLabel(defaultFlatLabel) { + style: TextStyle(defaultTextStyle) { + font: font(boxFontSize semibold); + } + minWidth: 32px; + align: align(top); + textFg: windowFg; +} dialogsMenuToggle: IconButton { width: 40px; diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 85e395cdb8..e812c8173a 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/text/text_utilities.h" #include "ui/text/text_options.h" #include "ui/dynamic_thumbnails.h" +#include "ui/vertical_list.h" #include "ui/painter.h" #include "ui/rect.h" #include "ui/ui_utility.h" @@ -58,8 +59,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/options.h" #include "lang/lang_keys.h" #include "lottie/lottie_icon.h" -#include "mainwindow.h" -#include "mainwidget.h" +#include "settings/settings_common.h" #include "storage/storage_account.h" #include "apiwrap.h" #include "main/main_session.h" @@ -80,6 +80,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_chat_filters.h" #include "base/qt/qt_common_adapters.h" #include "styles/style_dialogs.h" +#include "styles/style_boxes.h" #include "styles/style_chat.h" // popupMenuExpandedSeparator #include "styles/style_chat_helpers.h" #include "styles/style_color_indices.h" @@ -4075,9 +4076,18 @@ void InnerWidget::refreshEmpty() { if (state == EmptyState::None) { _emptyState = state; _empty.destroy(); + _emptyList.destroy(); + _emptyButton.destroy(); return; } else if (_emptyState == state) { _empty->setVisible(_state == WidgetState::Default); + if (_emptyList) { + _emptyList->setVisible(_state == WidgetState::Default); + _empty->setVisible(!_emptyList->isVisible()); + } + if (_emptyButton) { + _emptyButton->setVisible(_state == WidgetState::Default); + } return; } _emptyState = state; @@ -4108,7 +4118,6 @@ void InnerWidget::refreshEmpty() { return result; }); _empty.create(this, std::move(full), st::dialogsEmptyLabel); - resizeEmpty(); _empty->overrideLinkClickHandler([=] { if (_emptyState == EmptyState::NoContacts) { _controller->showAddContact(); @@ -4120,6 +4129,58 @@ void InnerWidget::refreshEmpty() { } }); _empty->setVisible(_state == WidgetState::Default); + + if (state == EmptyState::NoContacts) { + const auto isListVisible = _state == WidgetState::Default; + _emptyList.create(this); + _emptyList->setVisible(isListVisible); + + auto icon = ::Settings::CreateLottieIcon( + _emptyList, + { + .name = u"no_chats"_q, + .sizeOverride = Size(st::changePhoneIconSize), + }); + const auto iconWidget = _emptyList->add( + object_ptr>(_emptyList, std::move(icon.widget))); + Ui::AddSkip(_emptyList); + const auto label = _emptyList->add( + object_ptr( + _emptyList, + tr::lng_no_conversations(), + st::dialogEmptyButtonLabel)); + if (_state == WidgetState::Default) { + icon.animate(anim::repeat::once); + } + _emptyButton.create( + this, + tr::lng_no_conversations_button(), + st::dialogEmptyButton); + _emptyButton->setTextTransform( + Ui::RoundButton::TextTransform::NoTransform); + _emptyButton->setVisible(isListVisible); + _emptyButton->setClickedCallback([=, window = _controller] { + window->show(PrepareContactsBox(window)); + }); + geometryValue() | rpl::start_with_next([=](const QRect &r) { + const auto top = r.height() + - _emptyButton->height() + - st::dialogEmptyButtonSkip; + _emptyButton->moveToLeft(st::dialogEmptyButtonSkip, top); + }, _emptyButton->lifetime()); + geometryValue() | rpl::start_with_next([=](const QRect &r) { + const auto bottom = _emptyButton + ? (_emptyButton->height() + st::dialogEmptyButtonSkip) + : 0; + _emptyList->moveToLeft( + 0, + ((r.height() - bottom) - _emptyList->height()) / 2); + }, _emptyList->lifetime()); + + _empty->setVisible(!_emptyList->isVisible()); + } + + resizeEmpty(); } void InnerWidget::resizeEmpty() { @@ -4128,6 +4189,13 @@ void InnerWidget::resizeEmpty() { _empty->resizeToWidth(width() - 2 * skip); _empty->move(skip, (st::dialogsEmptyHeight - _empty->height()) / 2); } + if (_emptyList) { + _emptyList->resizeToWidth(width()); + } + if (_emptyButton) { + const auto skip = st::dialogEmptyButtonSkip; + _emptyButton->resizeToWidth(width() - 2 * skip); + } if (_searchEmpty) { _searchEmpty->resizeToWidth(width()); _searchEmpty->move(0, searchedOffset()); diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index c3c4a6b033..e54955ee2e 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -43,6 +43,8 @@ namespace Ui { class IconButton; class PopupMenu; class FlatLabel; +class VerticalLayout; +class RoundButton; struct ScrollToRequest; namespace Controls { enum class QuickDialogAction; @@ -619,6 +621,8 @@ private: object_ptr _searchEmpty = { nullptr }; SearchState _searchEmptyState; object_ptr _empty = { nullptr }; + object_ptr _emptyList = { nullptr }; + object_ptr _emptyButton = { nullptr }; Ui::DraggingScrollManager _draggingScroll;