From 7905694b31f960e49318a09652c175f0d1984bdf Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Wed, 4 Oct 2017 13:39:59 +0100 Subject: [PATCH] Add tabs and other types links to Info::Media. --- .../history/history_inner_widget.cpp | 2 +- .../history/history_inner_widget.h | 2 +- .../SourceFiles/history/history_widget.cpp | 4 +- Telegram/SourceFiles/info/info.style | 6 + .../SourceFiles/info/info_layer_widget.cpp | 1 + .../info/media/info_media_buttons.h | 129 ++++++++++ .../info/media/info_media_inner_widget.cpp | 233 ++++++++++++++++-- .../info/media/info_media_inner_widget.h | 43 +++- .../info/media/info_media_list_widget.cpp | 38 +++ .../info/media/info_media_list_widget.h | 60 +++++ .../info/media/info_media_widget.cpp | 12 +- .../profile/info_profile_inner_widget.cpp | 79 ++---- .../info/profile/info_profile_values.cpp | 13 - .../info/profile/info_profile_values.h | 14 -- Telegram/SourceFiles/ui/wrap/slide_wrap.cpp | 15 ++ Telegram/SourceFiles/ui/wrap/slide_wrap.h | 14 ++ Telegram/gyp/telegram_sources.txt | 3 + 17 files changed, 550 insertions(+), 118 deletions(-) create mode 100644 Telegram/SourceFiles/info/media/info_media_buttons.h create mode 100644 Telegram/SourceFiles/info/media/info_media_list_widget.cpp create mode 100644 Telegram/SourceFiles/info/media/info_media_list_widget.h diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 74d6278af..6e3a27a87 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -1579,7 +1579,7 @@ void HistoryInner::keyPressEvent(QKeyEvent *e) { } } -void HistoryInner::recountHeight() { +void HistoryInner::recountHistoryGeometry() { int visibleHeight = _scroll->height(); int oldHistoryPaddingTop = qMax(visibleHeight - historyHeight() - st::historyPaddingBottom, 0); if (_botAbout && !_botAbout->info->text.isEmpty()) { diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 0836f4513..b2bb2069b 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -47,7 +47,7 @@ public: void touchScrollUpdated(const QPoint &screenPos); QPoint mapPointToItem(QPoint p, HistoryItem *item); - void recountHeight(); + void recountHistoryGeometry(); void updateSize(); void repaintItem(const HistoryItem *item); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index c0d93e99a..0c12be8a9 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -4785,7 +4785,7 @@ int HistoryWidget::countAutomaticScrollTop() { void HistoryWidget::updateHistoryGeometry(bool initial, bool loadedDown, const ScrollChange &change) { if (!_history || (initial && _historyInited) || (!initial && !_historyInited)) return; if (_firstLoadRequest || _a_show.animating()) { - return; // scrollTopMax etc are not working after recountHeight() + return; // scrollTopMax etc are not working after recountHistoryGeometry() } auto newScrollHeight = height() - _topBar->height(); @@ -4868,7 +4868,7 @@ void HistoryWidget::updateHistoryGeometry(bool initial, bool loadedDown, const S } void HistoryWidget::updateListSize() { - _list->recountHeight(); + _list->recountHistoryGeometry(); auto washidden = _scroll->isHidden(); if (washidden) { _scroll->show(); diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style index 482f7e911..2dc5a4062 100644 --- a/Telegram/SourceFiles/info/info.style +++ b/Telegram/SourceFiles/info/info.style @@ -173,9 +173,15 @@ infoIconMembers: icon {{ "info_members", infoIconFg }}; infoIconNotifications: icon {{ "info_notifications", infoIconFg }}; infoIconActions: icon {{ "info_actions", infoIconFg }}; infoIconMediaPhoto: icon {{ "info_media_photo", infoIconFg }}; +infoIconMediaAudio: icon {{ "info_media_audio", infoIconFg }}; +infoIconMediaLink: icon {{ "info_media_link", infoIconFg }}; +infoIconMediaGroup: icon {{ "info_common_groups", infoIconFg }}; +infoIconMediaVoice: icon {{ "info_media_voice", infoIconFg }}; +infoIconMediaRound: icon {{ "info_media_round", infoIconFg }}; infoInformationIconPosition: point(25px, 12px); infoNotificationsIconPosition: point(20px, 5px); infoSharedMediaIconPosition: point(20px, 24px); +infoSharedMediaButtonIconPosition: point(20px, 3px); infoIconPosition: point(20px, 15px); infoLabeledOneLine: FlatLabel(defaultFlatLabel) { diff --git a/Telegram/SourceFiles/info/info_layer_widget.cpp b/Telegram/SourceFiles/info/info_layer_widget.cpp index 131bc6b1a..38b4abbba 100644 --- a/Telegram/SourceFiles/info/info_layer_widget.cpp +++ b/Telegram/SourceFiles/info/info_layer_widget.cpp @@ -57,6 +57,7 @@ LayerWidget::LayerWidget( void LayerWidget::setupHeightConsumers() { _content->desiredHeightValue() | rpl::start_with_next([this](int height) { + if (!_content) return; accumulate_max(_desiredHeight, height); resizeToWidth(width()); _content->forceContentRepaint(); diff --git a/Telegram/SourceFiles/info/media/info_media_buttons.h b/Telegram/SourceFiles/info/media/info_media_buttons.h new file mode 100644 index 000000000..b03488512 --- /dev/null +++ b/Telegram/SourceFiles/info/media/info_media_buttons.h @@ -0,0 +1,129 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include <rpl/mappers.h> +#include <rpl/map.h> +#include "lang/lang_keys.h" +#include "storage/storage_shared_media.h" +#include "info/info_memento.h" +#include "info/profile/info_profile_button.h" +#include "info/profile/info_profile_values.h" +#include "ui/wrap/slide_wrap.h" +#include "ui/wrap/vertical_layout.h" +#include "window/window_controller.h" +#include "styles/style_info.h" + +namespace Info { +namespace Media { + +using Type = Storage::SharedMediaType; + +inline auto MediaTextPhrase(Type type) { + switch (type) { + case Type::Photo: return lng_profile_photos; + case Type::Video: return lng_profile_videos; + case Type::File: return lng_profile_files; + case Type::MusicFile: return lng_profile_songs; + case Type::Link: return lng_profile_shared_links; + case Type::VoiceFile: return lng_profile_audios; + case Type::RoundFile: return lng_profile_rounds; + } + Unexpected("Type in setupSharedMedia()"); +}; + +inline auto MediaText(Type type) { + return [phrase = MediaTextPhrase(type)](int count) { + return phrase(lt_count, count); + }; +} + +template <typename Count, typename Text> +inline auto AddCountedButton( + Ui::VerticalLayout *parent, + Count &&count, + Text &&textFromCount, + Ui::MultiSlideTracker &tracker) { + using namespace rpl::mappers; + + using Button = Profile::Button; + auto forked = std::move(count) + | start_spawning(parent->lifetime()); + auto text = rpl::duplicate(forked) + | rpl::map([textFromCount](int count) { + return (count > 0) + ? textFromCount(count) + : QString(); + }); + auto button = parent->add(object_ptr<Ui::SlideWrap<Button>>( + parent, + object_ptr<Button>( + parent, + std::move(text), + st::infoSharedMediaButton)) + )->toggleOn( + rpl::duplicate(forked) + | rpl::map($1 > 0)); + tracker.track(button); + return button; +}; + +inline auto AddButton( + Ui::VerticalLayout *parent, + not_null<Window::Controller*> controller, + not_null<PeerData*> peer, + Type type, + Ui::MultiSlideTracker &tracker) { + auto result = AddCountedButton( + parent, + Profile::SharedMediaCountValue(peer, type), + MediaText(type), + tracker)->entity(); + result->addClickHandler([controller, peer, type] { + controller->showSection( + Info::Memento(peer->id, Section(type))); + }); + return std::move(result); +}; + +inline auto AddCommonGroupsButton( + Ui::VerticalLayout *parent, + not_null<Window::Controller*> controller, + not_null<UserData*> user, + Ui::MultiSlideTracker &tracker) { + auto result = AddCountedButton( + parent, + Profile::CommonGroupsCountValue(user), + [](int count) { + return lng_profile_common_groups(lt_count, count); + }, + tracker)->entity(); + result->addClickHandler([controller, user] { + controller->showSection( + Info::Memento( + user->id, + Section::Type::CommonGroups)); + }); + return std::move(result); +}; + +} // namespace Media +} // namespace Info \ No newline at end of file diff --git a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp index ba34fa3e6..ec84443ad 100644 --- a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp @@ -20,28 +20,160 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #include "info/media/info_media_inner_widget.h" -#include "ui/widgets/labels.h" +#include "boxes/abstract_box.h" +#include "info/media/info_media_list_widget.h" +#include "info/media/info_media_buttons.h" +#include "info/profile/info_profile_button.h" +#include "info/profile/info_profile_icon.h" +#include "ui/widgets/discrete_sliders.h" +#include "ui/wrap/vertical_layout.h" +#include "styles/style_info.h" +#include "lang/lang_keys.h" namespace Info { namespace Media { +namespace { + +using Type = InnerWidget::Type; + +base::optional<int> TypeToTabIndex(Type type) { + switch (type) { + case Type::Photo: return 0; + case Type::Video: return 1; + case Type::File: return 2; + } + return base::none; +} + +Type TabIndexToType(int index) { + switch (index) { + case 0: return Type::Photo; + case 1: return Type::Video; + case 2: return Type::File; + } + Unexpected("Index in Info::Media::TabIndexToType()"); +} + +} // namespace InnerWidget::InnerWidget( QWidget *parent, + rpl::producer<Wrap> &&wrap, + not_null<Window::Controller*> controller, not_null<PeerData*> peer, Type type) -: RpWidget(parent) -, _peer(peer) -, _type(type) { - auto text = qsl("Media Overview\n\n"); - auto label = object_ptr<Ui::FlatLabel>(this); - label->setText(text.repeated(50)); - widthValue() | rpl::start_with_next([inner = label.data()](int w) { - inner->resizeToWidth(w); - }, lifetime()); - label->heightValue() | rpl::start_with_next([this](int h) { - _rowsHeightFake = h; - resizeToWidth(width()); - }, lifetime()); +: RpWidget(parent) { + _list = setupList(controller, peer, type); + setupOtherTypes(std::move(wrap)); +} + +void InnerWidget::setupOtherTypes(rpl::producer<Wrap> &&wrap) { + std::move(wrap) + | rpl::start_with_next([this](Wrap value) { + if (value == Wrap::Side + && TypeToTabIndex(type())) { + createOtherTypes(); + } else { + _otherTabs = nullptr; + _otherTypes.destroy(); + refreshHeight(); + } + }, lifetime()); +} + +void InnerWidget::createOtherTypes() { + _otherTabs = nullptr; + _otherTypes.create(this); + + createTypeButtons(); + _otherTypes->add(object_ptr<BoxContentDivider>(_otherTypes)); + createTabs(); + + _otherTypes->heightValue() + | rpl::start_with_next( + [this] { refreshHeight(); }, + _otherTypes->lifetime()); +} + +void InnerWidget::createTypeButtons() { + auto wrap = _otherTypes->add(object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>( + _otherTypes, + object_ptr<Ui::VerticalLayout>(_otherTypes))); + auto content = wrap->entity(); + content->add(object_ptr<Ui::FixedHeightWidget>( + content, + st::infoProfileSkip)); + + auto tracker = Ui::MultiSlideTracker(); + auto addMediaButton = [&]( + Type type, + const style::icon &icon) { + auto result = AddButton( + content, + controller(), + peer(), + type, + tracker); + object_ptr<Profile::FloatingIcon>( + result, + icon, + st::infoSharedMediaButtonIconPosition); + }; + auto addCommonGroupsButton = [&]( + not_null<UserData*> user, + const style::icon &icon) { + auto result = AddCommonGroupsButton( + content, + controller(), + user, + tracker); + object_ptr<Profile::FloatingIcon>( + result, + icon, + st::infoSharedMediaButtonIconPosition); + }; + + addMediaButton(Type::MusicFile, st::infoIconMediaAudio); + addMediaButton(Type::Link, st::infoIconMediaLink); + if (auto user = peer()->asUser()) { + addCommonGroupsButton(user, st::infoIconMediaGroup); + } + addMediaButton(Type::VoiceFile, st::infoIconMediaVoice); + addMediaButton(Type::RoundFile, st::infoIconMediaRound); + + content->add(object_ptr<Ui::FixedHeightWidget>( + content, + st::infoProfileSkip)); + wrap->toggleOn(tracker.atLeastOneShownValue()); + wrap->finishAnimating(); +} + +void InnerWidget::createTabs() { + _otherTabs = _otherTypes->add(object_ptr<Ui::SettingsSlider>( + this, + st::infoTabs)); + auto sections = QStringList(); + sections.push_back(lang(lng_media_type_photos).toUpper()); + sections.push_back(lang(lng_media_type_videos).toUpper()); + sections.push_back(lang(lng_media_type_files).toUpper()); + _otherTabs->setSections(sections); + _otherTabs->sectionActivated() + | rpl::map([](int index) { return TabIndexToType(index); }) + | rpl::start_with_next( + [this](Type type) { + if (_list->type() != type) { + switchToTab(Memento(peer()->id, type)); + } + }, + _otherTabs->lifetime()); +} + +not_null<PeerData*> InnerWidget::peer() const { + return _list->peer(); +} + +Type InnerWidget::type() const { + return _list->type(); } void InnerWidget::visibleTopBottomUpdated( @@ -51,6 +183,50 @@ void InnerWidget::visibleTopBottomUpdated( _visibleBottom = visibleBottom; } +bool InnerWidget::showInternal(not_null<Memento*> memento) { + if (memento->peerId() != peer()->id) { + return false; + } + auto mementoType = memento->section().mediaType(); + if (mementoType == type()) { + restoreState(memento); + return true; + } else if (_otherTypes) { + if (TypeToTabIndex(mementoType)) { + switchToTab(std::move(*memento)); + return true; + } + } + return false; +} + +void InnerWidget::switchToTab(Memento &&memento) { + auto type = memento.section().mediaType(); + _list = setupList(controller(), peer(), type); + restoreState(&memento); + _otherTabs->setActiveSection(*TypeToTabIndex(type)); +} + +not_null<Window::Controller*> InnerWidget::controller() const { + return _list->controller(); +} + +object_ptr<ListWidget> InnerWidget::setupList( + not_null<Window::Controller*> controller, + not_null<PeerData*> peer, + Type type) { + auto result = object_ptr<ListWidget>( + this, + controller, + peer, + type); + result->heightValue() + | rpl::start_with_next( + [this] { refreshHeight(); }, + result->lifetime()); + return result; +} + void InnerWidget::saveState(not_null<Memento*> memento) { } @@ -58,7 +234,34 @@ void InnerWidget::restoreState(not_null<Memento*> memento) { } int InnerWidget::resizeGetHeight(int newWidth) { - return _rowsHeightFake; + _inResize = true; + auto guard = gsl::finally([this] { _inResize = false; }); + + if (_otherTypes) { + _otherTypes->resizeToWidth(newWidth); + } + _list->resizeToWidth(newWidth); + return recountHeight(); +} + +void InnerWidget::refreshHeight() { + if (_inResize) { + return; + } + resize(width(), recountHeight()); +} + +int InnerWidget::recountHeight() { + auto top = 0; + if (_otherTypes) { + _otherTypes->moveToLeft(0, top); + top += _otherTypes->heightNoMargins(); + } + if (_list) { + _list->moveToLeft(0, top); + top += _list->heightNoMargins(); + } + return top; } } // namespace Media diff --git a/Telegram/SourceFiles/info/media/info_media_inner_widget.h b/Telegram/SourceFiles/info/media/info_media_inner_widget.h index 07b75cf33..33c3bbe77 100644 --- a/Telegram/SourceFiles/info/media/info_media_inner_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_inner_widget.h @@ -23,23 +23,31 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "ui/rp_widget.h" #include "info/media/info_media_widget.h" +namespace Ui { +class SettingsSlider; +class VerticalLayout; +} // namespace Ui + namespace Info { namespace Media { +class Memento; +class ListWidget; + class InnerWidget final : public Ui::RpWidget { public: using Type = Widget::Type; InnerWidget( QWidget *parent, + rpl::producer<Wrap> &&wrap, + not_null<Window::Controller*> controller, not_null<PeerData*> peer, Type type); - not_null<PeerData*> peer() const { - return _peer; - } - Type type() const { - return _type; - } + not_null<PeerData*> peer() const; + Type type() const; + + bool showInternal(not_null<Memento*> memento); void saveState(not_null<Memento*> memento); void restoreState(not_null<Memento*> memento); @@ -51,10 +59,27 @@ protected: int visibleBottom) override; private: - not_null<PeerData*> _peer; - Type _type = Type::Photo; + int recountHeight(); + void refreshHeight(); + void setupOtherTypes(rpl::producer<Wrap> &&wrap); + void createOtherTypes(); + void createTypeButtons(); + void createTabs(); + void switchToTab(Memento &&memento); + + not_null<Window::Controller*> controller() const; + + object_ptr<ListWidget> setupList( + not_null<Window::Controller*> controller, + not_null<PeerData*> peer, + Type type); + + bool _inResize = false; + + Ui::SettingsSlider *_otherTabs = nullptr; + object_ptr<Ui::VerticalLayout> _otherTypes = { nullptr }; + object_ptr<ListWidget> _list = { nullptr }; - int _rowsHeightFake = 0; int _visibleTop = 0; int _visibleBottom = 0; diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp new file mode 100644 index 000000000..696f6fba1 --- /dev/null +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -0,0 +1,38 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +*/ +#include "info/media/info_media_list_widget.h" + +namespace Info { +namespace Media { + +ListWidget::ListWidget( + QWidget *parent, + not_null<Window::Controller*> controller, + not_null<PeerData*> peer, + Type type) +: RpWidget(parent) +, _controller(controller) +, _peer(peer) +, _type(type) { +} + +} // namespace Media +} // namespace Info diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.h b/Telegram/SourceFiles/info/media/info_media_list_widget.h new file mode 100644 index 000000000..141d2eabc --- /dev/null +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.h @@ -0,0 +1,60 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "ui/rp_widget.h" +#include "info/media/info_media_widget.h" + +namespace Window { +class Controller; +} // namespace Window + +namespace Info { +namespace Media { + +class ListWidget : public Ui::RpWidget { +public: + using Type = Widget::Type; + ListWidget( + QWidget *parent, + not_null<Window::Controller*> controller, + not_null<PeerData*> peer, + Type type); + + not_null<Window::Controller*> controller() const { + return _controller; + } + not_null<PeerData*> peer() const { + return _peer; + } + Type type() const { + return _type; + } + +private: + not_null<Window::Controller*> _controller; + not_null<PeerData*> _peer; + Type _type = Type::Photo; + +}; + +} // namespace Media +} // namespace Info diff --git a/Telegram/SourceFiles/info/media/info_media_widget.cpp b/Telegram/SourceFiles/info/media/info_media_widget.cpp index ba1296903..aa3a0f805 100644 --- a/Telegram/SourceFiles/info/media/info_media_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_widget.cpp @@ -47,8 +47,13 @@ Widget::Widget( not_null<Window::Controller*> controller, not_null<PeerData*> peer, Type type) -: ContentWidget(parent, std::move(wrap), controller, peer) { - _inner = setInnerWidget(object_ptr<InnerWidget>(this, peer, type)); +: ContentWidget(parent, rpl::duplicate(wrap), controller, peer) { + _inner = setInnerWidget(object_ptr<InnerWidget>( + this, + std::move(wrap), + controller, + peer, + type)); } Section Widget::section() const { @@ -61,8 +66,7 @@ Widget::Type Widget::type() const { bool Widget::showInternal(not_null<ContentMemento*> memento) { if (auto mediaMemento = dynamic_cast<Memento*>(memento.get())) { - if (mediaMemento->peerId() == peer()->id) { - restoreState(mediaMemento); + if (_inner->showInternal(mediaMemento)) { return true; } } diff --git a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp index 214eb567f..ec76957e8 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp @@ -30,6 +30,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "info/profile/info_profile_cover.h" #include "info/profile/info_profile_icon.h" #include "info/profile/info_profile_members.h" +#include "info/media/info_media_buttons.h" #include "boxes/abstract_box.h" #include "boxes/add_contact_box.h" #include "boxes/confirm_box.h" @@ -151,7 +152,7 @@ object_ptr<Ui::RpWidget> InnerWidget::setupDetails( object_ptr<Ui::RpWidget> InnerWidget::setupInfo( RpWidget *parent) const { auto result = object_ptr<Ui::VerticalLayout>(parent); - auto tracker = MultiLineTracker(); + auto tracker = Ui::MultiSlideTracker(); auto addInfoLine = [&]( LangKey label, rpl::producer<TextWithEntities> &&text, @@ -222,7 +223,7 @@ void InnerWidget::setupUserButtons( Ui::VerticalLayout *wrap, not_null<UserData*> user) const { using namespace rpl::mappers; - auto tracker = MultiLineTracker(); + auto tracker = Ui::MultiSlideTracker(); auto topSkip = wrap->add(createSlideSkipWidget(wrap)); auto addButton = [&](auto &&text) { auto result = wrap->add(object_ptr<Ui::SlideWrap<Button>>( @@ -264,67 +265,26 @@ void InnerWidget::setupUserButtons( object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia( RpWidget *parent) { using namespace rpl::mappers; + using MediaType = Media::Type; auto content = object_ptr<Ui::VerticalLayout>(parent); - auto tracker = MultiLineTracker(); - auto addButton = [&]( - auto &&count, - auto textFromCount) { - auto forked = std::move(count) - | start_spawning(content->lifetime()); - auto button = content->add(object_ptr<Ui::SlideWrap<Button>>( - content, - object_ptr<Button>( - content, - rpl::duplicate(forked) - | rpl::map([textFromCount](int count) { - return (count > 0) - ? textFromCount(count) - : QString(); - }), - st::infoSharedMediaButton)) - )->toggleOn( - rpl::duplicate(forked) - | rpl::map($1 > 0)); - tracker.track(button); - return button; - }; - using MediaType = Storage::SharedMediaType; - auto mediaText = [](MediaType type) { - switch (type) { - case MediaType::Photo: return lng_profile_photos; - case MediaType::Video: return lng_profile_videos; - case MediaType::File: return lng_profile_files; - case MediaType::MusicFile: return lng_profile_songs; - case MediaType::Link: return lng_profile_shared_links; - case MediaType::VoiceFile: return lng_profile_audios; - case MediaType::RoundFile: return lng_profile_rounds; - } - Unexpected("Type in setupSharedMedia()"); - }; + auto tracker = Ui::MultiSlideTracker(); auto addMediaButton = [&](MediaType type) { - return addButton( - SharedMediaCountValue(_peer, type), - [phrase = mediaText(type)](int count) { - return phrase(lt_count, count); - } - )->entity()->addClickHandler([this, peer = _peer, type] { - _controller->showSection( - Info::Memento(peer->id, Section(type))); - }); + return Media::AddButton( + content, + _controller, + peer(), + type, + tracker); }; auto addCommonGroupsButton = [&](not_null<UserData*> user) { - return addButton( - CommonGroupsCountValue(user), - [](int count) { - return lng_profile_common_groups(lt_count, count); - } - )->entity()->addClickHandler([this, peer = _peer] { - _controller->showSection( - ::Profile::CommonGroups::SectionMemento( - peer->asUser())); - }); + return Media::AddCommonGroupsButton( + content, + _controller, + user, + tracker); }; + addMediaButton(MediaType::Photo); addMediaButton(MediaType::Video); addMediaButton(MediaType::File); @@ -343,8 +303,9 @@ object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia( result->toggleOn(tracker.atLeastOneShownValue()); auto layout = result->entity(); - layout->add(object_ptr<BoxContentDivider>(result)); - _sharedMediaCover = layout->add(object_ptr<SharedMediaCover>(layout)); + layout->add(object_ptr<BoxContentDivider>(layout)); + _sharedMediaCover = layout->add( + object_ptr<SharedMediaCover>(layout)); if (canHideDetailsEver()) { _sharedMediaCover->setToggleShown(canHideDetails()); _sharedMediaWrap = layout->add(object_ptr<Ui::SlideWrap<>>( diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.cpp b/Telegram/SourceFiles/info/profile/info_profile_values.cpp index c3d8d1cab..2c74b8365 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_values.cpp @@ -240,18 +240,5 @@ rpl::producer<bool> CanAddMemberValue( return rpl::single(false); } -rpl::producer<bool> MultiLineTracker::atLeastOneShownValue() const { - auto shown = std::vector<rpl::producer<bool>>(); - shown.reserve(_widgets.size()); - for (auto &widget : _widgets) { - shown.push_back(widget->toggledValue()); - } - return rpl::combine( - std::move(shown), - [](const std::vector<bool> &values) { - return base::find(values, true) != values.end(); - }); -} - } // namespace Profile } // namespace Info diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.h b/Telegram/SourceFiles/info/profile/info_profile_values.h index cc0c9ba63..0b5817962 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.h +++ b/Telegram/SourceFiles/info/profile/info_profile_values.h @@ -77,19 +77,5 @@ rpl::producer<int> CommonGroupsCountValue( rpl::producer<bool> CanAddMemberValue( not_null<PeerData*> peer); -class MultiLineTracker { -public: - template <typename Widget> - void track(const Ui::SlideWrap<Widget> *wrap) { - _widgets.push_back(wrap); - } - - rpl::producer<bool> atLeastOneShownValue() const; - -private: - std::vector<const Ui::SlideWrap<Ui::RpWidget>*> _widgets; - -}; - } // namespace Profile } // namespace Info diff --git a/Telegram/SourceFiles/ui/wrap/slide_wrap.cpp b/Telegram/SourceFiles/ui/wrap/slide_wrap.cpp index 412822f4d..7e652626b 100644 --- a/Telegram/SourceFiles/ui/wrap/slide_wrap.cpp +++ b/Telegram/SourceFiles/ui/wrap/slide_wrap.cpp @@ -20,6 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #include "ui/wrap/slide_wrap.h" +#include <rpl/combine.h> + namespace Ui { SlideWrap<RpWidget>::SlideWrap( @@ -144,5 +146,18 @@ void SlideWrap<RpWidget>::wrappedSizeUpdated(QSize size) { } } +rpl::producer<bool> MultiSlideTracker::atLeastOneShownValue() const { + auto shown = std::vector<rpl::producer<bool>>(); + shown.reserve(_widgets.size()); + for (auto &widget : _widgets) { + shown.push_back(widget->toggledValue()); + } + return rpl::combine( + std::move(shown), + [](const std::vector<bool> &values) { + return base::find(values, true) != values.end(); + }); +} + } // namespace Ui diff --git a/Telegram/SourceFiles/ui/wrap/slide_wrap.h b/Telegram/SourceFiles/ui/wrap/slide_wrap.h index 70414fc77..811e53f7b 100644 --- a/Telegram/SourceFiles/ui/wrap/slide_wrap.h +++ b/Telegram/SourceFiles/ui/wrap/slide_wrap.h @@ -136,5 +136,19 @@ inline object_ptr<SlideWrap<>> CreateSlideSkipWidget( QMargins(0, 0, 0, skip)); } +class MultiSlideTracker { +public: + template <typename Widget> + void track(const Ui::SlideWrap<Widget> *wrap) { + _widgets.push_back(wrap); + } + + rpl::producer<bool> atLeastOneShownValue() const; + +private: + std::vector<const Ui::SlideWrap<Ui::RpWidget>*> _widgets; + +}; + } // namespace Ui diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index dfd6b606b..47b2b3685 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -221,8 +221,11 @@ <(src_loc)/info/info_top_bar.h <(src_loc)/info/info_wrap_widget.cpp <(src_loc)/info/info_wrap_widget.h +<(src_loc)/info/media/info_media_buttons.h <(src_loc)/info/media/info_media_inner_widget.cpp <(src_loc)/info/media/info_media_inner_widget.h +<(src_loc)/info/media/info_media_list_widget.cpp +<(src_loc)/info/media/info_media_list_widget.h <(src_loc)/info/media/info_media_widget.cpp <(src_loc)/info/media/info_media_widget.h <(src_loc)/info/profile/info_profile_button.cpp