/* 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/profile/info_profile_inner_widget.h" #include #include #include #include "info/info_memento.h" #include "info/info_controller.h" #include "info/profile/info_profile_button.h" #include "info/profile/info_profile_widget.h" #include "info/profile/info_profile_text.h" #include "info/profile/info_profile_values.h" #include "info/profile/info_profile_cover.h" #include "info/profile/info_profile_icon.h" #include "info/profile/info_profile_members.h" #include "info/profile/info_profile_actions.h" #include "info/media/info_media_buttons.h" #include "boxes/abstract_box.h" #include "boxes/add_contact_box.h" #include "boxes/confirm_box.h" #include "boxes/report_box.h" #include "mainwidget.h" #include "auth_session.h" #include "apiwrap.h" #include "window/main_window.h" #include "window/window_controller.h" #include "storage/storage_shared_media.h" #include "lang/lang_keys.h" #include "styles/style_info.h" #include "styles/style_boxes.h" #include "ui/widgets/buttons.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/scroll_area.h" #include "ui/widgets/shadow.h" #include "ui/wrap/slide_wrap.h" #include "ui/wrap/vertical_layout.h" #include "data/data_shared_media.h" namespace Info { namespace Profile { InnerWidget::InnerWidget( QWidget *parent, not_null controller) : RpWidget(parent) , _controller(controller) , _peer(_controller->peer()) , _migrated(_controller->migrated()) , _content(setupContent(this)) { _content->heightValue() | rpl::start_with_next([this](int height) { if (!_inResize) { resizeToWidth(width()); updateDesiredHeight(); } }, lifetime()); } bool InnerWidget::canHideDetailsEver() const { return false;// (_peer->isChat() || _peer->isMegagroup()); } rpl::producer InnerWidget::canHideDetails() const { using namespace rpl::mappers; return MembersCountValue(_peer) | rpl::map(_1 > 0); } object_ptr InnerWidget::setupContent( not_null parent) { auto result = object_ptr(parent); _cover = result->add(object_ptr( result, _controller, _peer)); _cover->setOnlineCount(rpl::single(0)); auto details = SetupDetails(_controller, parent, _peer); if (canHideDetailsEver()) { _cover->setToggleShown(canHideDetails()); _infoWrap = result->add(object_ptr>( result, std::move(details)) )->setDuration( st::infoSlideDuration )->toggleOn( _cover->toggledValue() ); } else { result->add(std::move(details)); } result->add(setupSharedMedia(result.data())); if (auto members = SetupChannelMembers(_controller, result.data(), _peer)) { result->add(std::move(members)); } result->add(object_ptr(result)); if (auto actions = SetupActions(_controller, result.data(), _peer)) { result->add(std::move(actions)); } if (_peer->isChat() || _peer->isMegagroup()) { _members = result->add(object_ptr( result, _controller, _peer) ); _members->scrollToRequests() | rpl::start_with_next([this](Ui::ScrollToRequest request) { auto min = (request.ymin < 0) ? request.ymin : mapFromGlobal(_members->mapToGlobal({ 0, request.ymin })).y(); auto max = (request.ymin < 0) ? mapFromGlobal(_members->mapToGlobal({ 0, 0 })).y() : (request.ymax < 0) ? request.ymax : mapFromGlobal(_members->mapToGlobal({ 0, request.ymax })).y(); _scrollToRequests.fire({ min, max }); }, _members->lifetime()); _cover->setOnlineCount(_members->onlineCountValue()); } return std::move(result); } object_ptr InnerWidget::setupSharedMedia( not_null parent) { using namespace rpl::mappers; using MediaType = Media::Type; auto content = object_ptr(parent); auto tracker = Ui::MultiSlideTracker(); auto addMediaButton = [&]( MediaType type, const style::icon &icon) { auto result = Media::AddButton( content, _controller, _peer, _migrated, type, tracker); object_ptr( result, icon, st::infoSharedMediaButtonIconPosition); }; auto addCommonGroupsButton = [&]( not_null user, const style::icon &icon) { auto result = Media::AddCommonGroupsButton( content, _controller, user, tracker); object_ptr( result, icon, st::infoSharedMediaButtonIconPosition); }; addMediaButton(MediaType::Photo, st::infoIconMediaPhoto); addMediaButton(MediaType::Video, st::infoIconMediaVideo); addMediaButton(MediaType::File, st::infoIconMediaFile); addMediaButton(MediaType::MusicFile, st::infoIconMediaAudio); addMediaButton(MediaType::Link, st::infoIconMediaLink); if (auto user = _peer->asUser()) { addCommonGroupsButton(user, st::infoIconMediaGroup); } addMediaButton(MediaType::VoiceFile, st::infoIconMediaVoice); // addMediaButton(MediaType::RoundFile, st::infoIconMediaRound); auto result = object_ptr>( parent, object_ptr(parent) ); // Allows removing shared media links in third column. // Was done for tabs support. // //using ToggledData = std::tuple; //rpl::combine( // tracker.atLeastOneShownValue(), // _controller->wrapValue(), // _isStackBottom.value()) // | rpl::combine_previous(ToggledData()) // | rpl::start_with_next([wrap = result.data()]( // const ToggledData &was, // const ToggledData &now) { // bool wasOneShown, wasStackBottom, nowOneShown, nowStackBottom; // Wrap wasWrap, nowWrap; // std::tie(wasOneShown, wasWrap, wasStackBottom) = was; // std::tie(nowOneShown, nowWrap, nowStackBottom) = now; // // MSVC Internal Compiler Error // //auto [wasOneShown, wasWrap, wasStackBottom] = was; // //auto [nowOneShown, nowWrap, nowStackBottom] = now; // wrap->toggle( // nowOneShown && (nowWrap != Wrap::Side || !nowStackBottom), // (wasStackBottom == nowStackBottom && wasWrap == nowWrap) // ? anim::type::normal // : anim::type::instant); // }, result->lifetime()); // // Using that instead result->setDuration( st::infoSlideDuration )->toggleOn( tracker.atLeastOneShownValue() ); auto layout = result->entity(); layout->add(object_ptr(layout)); layout->add(object_ptr( layout, st::infoSharedMediaBottomSkip) )->setAttribute(Qt::WA_TransparentForMouseEvents); layout->add(std::move(content)); layout->add(object_ptr( layout, st::infoSharedMediaBottomSkip) )->setAttribute(Qt::WA_TransparentForMouseEvents); _sharedMediaWrap = result; return std::move(result); } int InnerWidget::countDesiredHeight() const { return _content->height() + (_members ? (_members->desiredHeight() - _members->height()) : 0); } void InnerWidget::visibleTopBottomUpdated( int visibleTop, int visibleBottom) { setChildVisibleTopBottom(_content, visibleTop, visibleBottom); } void InnerWidget::saveState(not_null memento) { memento->setInfoExpanded(_cover->toggled()); if (_members) { memento->setMembersState(_members->saveState()); } } void InnerWidget::restoreState(not_null memento) { _cover->toggle(memento->infoExpanded(), anim::type::instant); if (_members) { _members->restoreState(memento->membersState()); } if (_infoWrap) { _infoWrap->finishAnimating(); } if (_sharedMediaWrap) { _sharedMediaWrap->finishAnimating(); } } rpl::producer InnerWidget::scrollToRequests() const { return _scrollToRequests.events(); } rpl::producer InnerWidget::desiredHeightValue() const { return _desiredHeight.events_starting_with(countDesiredHeight()); } int InnerWidget::resizeGetHeight(int newWidth) { _inResize = true; auto guard = gsl::finally([&] { _inResize = false; }); _content->resizeToWidth(newWidth); _content->moveToLeft(0, 0); updateDesiredHeight(); return _content->heightNoMargins(); } } // namespace Profile } // namespace Info