2017-11-07 11:53:05 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
2018-01-03 10:23:14 +00:00
|
|
|
the official desktop application for the Telegram messaging service.
|
2017-11-07 11:53:05 +00:00
|
|
|
|
2018-01-03 10:23:14 +00:00
|
|
|
For license and copyright information please follow this link:
|
|
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
2017-11-07 11:53:05 +00:00
|
|
|
*/
|
|
|
|
#include "info/profile/info_profile_actions.h"
|
|
|
|
|
|
|
|
#include <rpl/flatten_latest.h>
|
2017-11-10 19:19:43 +00:00
|
|
|
#include <rpl/combine.h>
|
|
|
|
#include "data/data_peer_values.h"
|
2018-02-08 09:20:14 +00:00
|
|
|
#include "data/data_session.h"
|
|
|
|
#include "data/data_feed.h"
|
2019-01-04 11:09:48 +00:00
|
|
|
#include "data/data_channel.h"
|
|
|
|
#include "data/data_user.h"
|
2017-11-07 11:53:05 +00:00
|
|
|
#include "ui/wrap/vertical_layout.h"
|
|
|
|
#include "ui/wrap/padding_wrap.h"
|
|
|
|
#include "ui/wrap/slide_wrap.h"
|
|
|
|
#include "ui/widgets/shadow.h"
|
2017-11-10 17:51:59 +00:00
|
|
|
#include "ui/widgets/labels.h"
|
|
|
|
#include "ui/toast/toast.h"
|
2017-11-07 11:53:05 +00:00
|
|
|
#include "boxes/abstract_box.h"
|
|
|
|
#include "boxes/confirm_box.h"
|
|
|
|
#include "boxes/peer_list_box.h"
|
|
|
|
#include "boxes/peer_list_controllers.h"
|
|
|
|
#include "boxes/add_contact_box.h"
|
|
|
|
#include "boxes/report_box.h"
|
|
|
|
#include "lang/lang_keys.h"
|
|
|
|
#include "info/info_controller.h"
|
2017-11-17 16:06:20 +00:00
|
|
|
#include "info/info_memento.h"
|
2017-11-07 11:53:05 +00:00
|
|
|
#include "info/profile/info_profile_icon.h"
|
|
|
|
#include "info/profile/info_profile_values.h"
|
|
|
|
#include "info/profile/info_profile_button.h"
|
|
|
|
#include "info/profile/info_profile_text.h"
|
2018-11-20 15:36:36 +00:00
|
|
|
#include "support/support_helper.h"
|
2017-11-07 11:53:05 +00:00
|
|
|
#include "window/window_controller.h"
|
2017-11-07 13:13:41 +00:00
|
|
|
#include "window/window_peer_menu.h"
|
2017-11-07 11:53:05 +00:00
|
|
|
#include "mainwidget.h"
|
|
|
|
#include "auth_session.h"
|
2019-01-21 13:42:21 +00:00
|
|
|
#include "core/application.h"
|
2017-11-07 11:53:05 +00:00
|
|
|
#include "apiwrap.h"
|
|
|
|
#include "styles/style_info.h"
|
|
|
|
#include "styles/style_boxes.h"
|
|
|
|
|
|
|
|
namespace Info {
|
|
|
|
namespace Profile {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
object_ptr<Ui::RpWidget> CreateSkipWidget(
|
|
|
|
not_null<Ui::RpWidget*> parent) {
|
|
|
|
return Ui::CreateSkipWidget(parent, st::infoProfileSkip);
|
|
|
|
}
|
|
|
|
|
|
|
|
object_ptr<Ui::SlideWrap<>> CreateSlideSkipWidget(
|
|
|
|
not_null<Ui::RpWidget*> parent) {
|
2017-11-19 11:37:15 +00:00
|
|
|
auto result = Ui::CreateSlideSkipWidget(
|
|
|
|
parent,
|
|
|
|
st::infoProfileSkip);
|
|
|
|
result->setDuration(st::infoSlideDuration);
|
|
|
|
return result;
|
2017-11-07 11:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Text, typename ToggleOn, typename Callback>
|
|
|
|
auto AddActionButton(
|
|
|
|
not_null<Ui::VerticalLayout*> parent,
|
|
|
|
Text &&text,
|
|
|
|
ToggleOn &&toggleOn,
|
|
|
|
Callback &&callback,
|
|
|
|
const style::InfoProfileButton &st
|
|
|
|
= st::infoSharedMediaButton) {
|
|
|
|
auto result = parent->add(object_ptr<Ui::SlideWrap<Button>>(
|
|
|
|
parent,
|
|
|
|
object_ptr<Button>(
|
|
|
|
parent,
|
|
|
|
std::move(text),
|
|
|
|
st))
|
|
|
|
);
|
2017-11-19 11:37:15 +00:00
|
|
|
result->setDuration(
|
|
|
|
st::infoSlideDuration
|
|
|
|
)->toggleOn(
|
2017-11-07 11:53:05 +00:00
|
|
|
std::move(toggleOn)
|
|
|
|
)->entity()->addClickHandler(std::move(callback));
|
2017-11-17 17:02:49 +00:00
|
|
|
result->finishAnimating();
|
2017-11-07 11:53:05 +00:00
|
|
|
return result;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename Text, typename ToggleOn, typename Callback>
|
|
|
|
auto AddMainButton(
|
|
|
|
not_null<Ui::VerticalLayout*> parent,
|
|
|
|
Text &&text,
|
|
|
|
ToggleOn &&toggleOn,
|
|
|
|
Callback &&callback,
|
|
|
|
Ui::MultiSlideTracker &tracker) {
|
|
|
|
tracker.track(AddActionButton(
|
|
|
|
parent,
|
|
|
|
std::move(text) | ToUpperValue(),
|
|
|
|
std::move(toggleOn),
|
|
|
|
std::move(callback),
|
|
|
|
st::infoMainButton));
|
|
|
|
}
|
|
|
|
|
|
|
|
class DetailsFiller {
|
|
|
|
public:
|
|
|
|
DetailsFiller(
|
|
|
|
not_null<Controller*> controller,
|
|
|
|
not_null<Ui::RpWidget*> parent,
|
|
|
|
not_null<PeerData*> peer);
|
|
|
|
|
|
|
|
object_ptr<Ui::RpWidget> fill();
|
|
|
|
|
|
|
|
private:
|
|
|
|
object_ptr<Ui::RpWidget> setupInfo();
|
|
|
|
object_ptr<Ui::RpWidget> setupMuteToggle();
|
|
|
|
void setupMainButtons();
|
|
|
|
Ui::MultiSlideTracker fillUserButtons(
|
|
|
|
not_null<UserData*> user);
|
|
|
|
Ui::MultiSlideTracker fillChannelButtons(
|
|
|
|
not_null<ChannelData*> channel);
|
|
|
|
|
|
|
|
template <
|
|
|
|
typename Widget,
|
|
|
|
typename = std::enable_if_t<
|
|
|
|
std::is_base_of_v<Ui::RpWidget, Widget>>>
|
|
|
|
Widget *add(
|
|
|
|
object_ptr<Widget> &&child,
|
|
|
|
const style::margins &margin = style::margins()) {
|
|
|
|
return _wrap->add(
|
|
|
|
std::move(child),
|
|
|
|
margin);
|
|
|
|
}
|
|
|
|
|
|
|
|
not_null<Controller*> _controller;
|
|
|
|
not_null<Ui::RpWidget*> _parent;
|
|
|
|
not_null<PeerData*> _peer;
|
|
|
|
object_ptr<Ui::VerticalLayout> _wrap;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
class ActionsFiller {
|
|
|
|
public:
|
|
|
|
ActionsFiller(
|
|
|
|
not_null<Controller*> controller,
|
|
|
|
not_null<Ui::RpWidget*> parent,
|
|
|
|
not_null<PeerData*> peer);
|
|
|
|
|
|
|
|
object_ptr<Ui::RpWidget> fill();
|
|
|
|
|
|
|
|
private:
|
|
|
|
void addInviteToGroupAction(not_null<UserData*> user);
|
|
|
|
void addShareContactAction(not_null<UserData*> user);
|
|
|
|
void addEditContactAction(not_null<UserData*> user);
|
|
|
|
void addDeleteContactAction(not_null<UserData*> user);
|
|
|
|
void addClearHistoryAction(not_null<UserData*> user);
|
|
|
|
void addDeleteConversationAction(not_null<UserData*> user);
|
|
|
|
void addBotCommandActions(not_null<UserData*> user);
|
|
|
|
void addReportAction();
|
|
|
|
void addBlockAction(not_null<UserData*> user);
|
|
|
|
void addLeaveChannelAction(not_null<ChannelData*> channel);
|
|
|
|
void addJoinChannelAction(not_null<ChannelData*> channel);
|
|
|
|
void fillUserActions(not_null<UserData*> user);
|
|
|
|
void fillChannelActions(not_null<ChannelData*> channel);
|
|
|
|
|
|
|
|
not_null<Controller*> _controller;
|
|
|
|
not_null<Ui::RpWidget*> _parent;
|
|
|
|
not_null<PeerData*> _peer;
|
|
|
|
object_ptr<Ui::VerticalLayout> _wrap = { nullptr };
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2018-02-07 12:40:37 +00:00
|
|
|
class FeedDetailsFiller {
|
|
|
|
public:
|
|
|
|
FeedDetailsFiller(
|
|
|
|
not_null<Controller*> controller,
|
|
|
|
not_null<Ui::RpWidget*> parent,
|
|
|
|
not_null<Data::Feed*> feed);
|
|
|
|
|
|
|
|
object_ptr<Ui::RpWidget> fill();
|
|
|
|
|
|
|
|
private:
|
|
|
|
object_ptr<Ui::RpWidget> setupDefaultToggle();
|
|
|
|
|
|
|
|
template <
|
|
|
|
typename Widget,
|
|
|
|
typename = std::enable_if_t<
|
|
|
|
std::is_base_of_v<Ui::RpWidget, Widget>>>
|
|
|
|
Widget *add(
|
|
|
|
object_ptr<Widget> &&child,
|
|
|
|
const style::margins &margin = style::margins()) {
|
|
|
|
return _wrap->add(
|
|
|
|
std::move(child),
|
|
|
|
margin);
|
|
|
|
}
|
|
|
|
|
|
|
|
not_null<Controller*> _controller;
|
|
|
|
not_null<Ui::RpWidget*> _parent;
|
|
|
|
not_null<Data::Feed*> _feed;
|
|
|
|
object_ptr<Ui::VerticalLayout> _wrap;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2017-11-07 11:53:05 +00:00
|
|
|
DetailsFiller::DetailsFiller(
|
|
|
|
not_null<Controller*> controller,
|
|
|
|
not_null<Ui::RpWidget*> parent,
|
|
|
|
not_null<PeerData*> peer)
|
|
|
|
: _controller(controller)
|
|
|
|
, _parent(parent)
|
|
|
|
, _peer(peer)
|
|
|
|
, _wrap(_parent) {
|
|
|
|
}
|
|
|
|
|
|
|
|
object_ptr<Ui::RpWidget> DetailsFiller::setupInfo() {
|
|
|
|
auto result = object_ptr<Ui::VerticalLayout>(_wrap);
|
|
|
|
auto tracker = Ui::MultiSlideTracker();
|
2018-11-20 15:36:36 +00:00
|
|
|
auto addInfoLineGeneric = [&](
|
|
|
|
rpl::producer<QString> label,
|
2017-11-07 11:53:05 +00:00
|
|
|
rpl::producer<TextWithEntities> &&text,
|
|
|
|
const style::FlatLabel &textSt = st::infoLabeled) {
|
2017-11-10 17:51:59 +00:00
|
|
|
auto line = CreateTextWithLabel(
|
2017-11-07 11:53:05 +00:00
|
|
|
result,
|
2018-11-20 15:36:36 +00:00
|
|
|
std::move(label) | WithEmptyEntities(),
|
2017-11-07 11:53:05 +00:00
|
|
|
std::move(text),
|
|
|
|
textSt,
|
2017-11-10 17:51:59 +00:00
|
|
|
st::infoProfileLabeledPadding);
|
|
|
|
tracker.track(result->add(std::move(line.wrap)));
|
|
|
|
return line.text;
|
2017-11-07 11:53:05 +00:00
|
|
|
};
|
2018-11-20 15:36:36 +00:00
|
|
|
auto addInfoLine = [&](
|
|
|
|
LangKey label,
|
|
|
|
rpl::producer<TextWithEntities> &&text,
|
|
|
|
const style::FlatLabel &textSt = st::infoLabeled) {
|
|
|
|
return addInfoLineGeneric(
|
|
|
|
Lang::Viewer(label),
|
|
|
|
std::move(text),
|
|
|
|
textSt);
|
|
|
|
};
|
2017-11-07 11:53:05 +00:00
|
|
|
auto addInfoOneLine = [&](
|
|
|
|
LangKey label,
|
2017-11-10 17:51:59 +00:00
|
|
|
rpl::producer<TextWithEntities> &&text,
|
|
|
|
const QString &contextCopyText) {
|
|
|
|
auto result = addInfoLine(
|
2017-11-07 11:53:05 +00:00
|
|
|
label,
|
|
|
|
std::move(text),
|
|
|
|
st::infoLabeledOneLine);
|
2017-11-10 17:51:59 +00:00
|
|
|
result->setDoubleClickSelectsParagraph(true);
|
|
|
|
result->setContextCopyText(contextCopyText);
|
|
|
|
return result;
|
2017-11-07 11:53:05 +00:00
|
|
|
};
|
|
|
|
if (auto user = _peer->asUser()) {
|
2018-11-20 15:36:36 +00:00
|
|
|
if (Auth().supportMode()) {
|
|
|
|
addInfoLineGeneric(
|
|
|
|
Auth().supportHelper().infoLabelValue(user),
|
|
|
|
Auth().supportHelper().infoTextValue(user));
|
|
|
|
}
|
|
|
|
|
2017-11-10 17:51:59 +00:00
|
|
|
addInfoOneLine(
|
|
|
|
lng_info_mobile_label,
|
|
|
|
PhoneValue(user),
|
|
|
|
lang(lng_profile_copy_phone));
|
2017-11-07 11:53:05 +00:00
|
|
|
if (user->botInfo) {
|
|
|
|
addInfoLine(lng_info_about_label, AboutValue(user));
|
|
|
|
} else {
|
|
|
|
addInfoLine(lng_info_bio_label, BioValue(user));
|
|
|
|
}
|
2017-11-10 17:51:59 +00:00
|
|
|
addInfoOneLine(
|
|
|
|
lng_info_username_label,
|
|
|
|
UsernameValue(user),
|
|
|
|
lang(lng_context_copy_mention));
|
2017-11-07 11:53:05 +00:00
|
|
|
} else {
|
2017-12-22 07:05:20 +00:00
|
|
|
auto linkText = LinkValue(
|
|
|
|
_peer
|
|
|
|
) | rpl::map([](const QString &link) {
|
|
|
|
auto result = TextWithEntities{ link, {} };
|
|
|
|
if (!link.isEmpty()) {
|
|
|
|
auto remove = qstr("https://");
|
|
|
|
if (result.text.startsWith(remove)) {
|
|
|
|
result.text.remove(0, remove.size());
|
2017-11-10 17:51:59 +00:00
|
|
|
}
|
2017-12-22 07:05:20 +00:00
|
|
|
result.entities.push_back(EntityInText(
|
|
|
|
EntityInTextCustomUrl,
|
|
|
|
0,
|
|
|
|
result.text.size(),
|
|
|
|
link));
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
});
|
2017-11-10 17:51:59 +00:00
|
|
|
auto link = addInfoOneLine(
|
|
|
|
lng_info_link_label,
|
|
|
|
std::move(linkText),
|
|
|
|
QString());
|
2018-06-22 19:46:20 +00:00
|
|
|
link->setClickHandlerFilter([peer = _peer](auto&&...) {
|
2019-01-21 13:42:21 +00:00
|
|
|
auto link = Core::App().createInternalLinkFull(
|
2017-11-10 17:51:59 +00:00
|
|
|
peer->userName());
|
|
|
|
if (!link.isEmpty()) {
|
2019-01-18 11:26:43 +00:00
|
|
|
QApplication::clipboard()->setText(link);
|
2017-11-10 17:51:59 +00:00
|
|
|
Ui::Toast::Show(lang(lng_username_copied));
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
2017-11-07 11:53:05 +00:00
|
|
|
addInfoLine(lng_info_about_label, AboutValue(_peer));
|
|
|
|
}
|
2017-12-05 14:07:01 +00:00
|
|
|
if (!_peer->isSelf()) {
|
|
|
|
// No notifications toggle for Self => no separator.
|
|
|
|
result->add(object_ptr<Ui::SlideWrap<>>(
|
|
|
|
result,
|
|
|
|
object_ptr<Ui::PlainShadow>(result),
|
|
|
|
st::infoProfileSeparatorPadding)
|
|
|
|
)->setDuration(
|
|
|
|
st::infoSlideDuration
|
|
|
|
)->toggleOn(
|
|
|
|
std::move(tracker).atLeastOneShownValue()
|
|
|
|
);
|
|
|
|
}
|
2017-11-07 11:53:05 +00:00
|
|
|
object_ptr<FloatingIcon>(
|
|
|
|
result,
|
|
|
|
st::infoIconInformation,
|
|
|
|
st::infoInformationIconPosition);
|
|
|
|
return std::move(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
object_ptr<Ui::RpWidget> DetailsFiller::setupMuteToggle() {
|
2017-12-04 17:46:03 +00:00
|
|
|
const auto peer = _peer;
|
2017-11-07 11:53:05 +00:00
|
|
|
auto result = object_ptr<Button>(
|
|
|
|
_wrap,
|
|
|
|
Lang::Viewer(lng_profile_enable_notifications),
|
|
|
|
st::infoNotificationsButton);
|
|
|
|
result->toggleOn(
|
|
|
|
NotificationsEnabledValue(peer)
|
|
|
|
)->addClickHandler([=] {
|
2018-04-09 17:48:29 +00:00
|
|
|
const auto muteForSeconds = Auth().data().notifyIsMuted(peer)
|
|
|
|
? 0
|
|
|
|
: Data::NotifySettings::kDefaultMutePeriod;
|
|
|
|
Auth().data().updateNotifySettings(peer, muteForSeconds);
|
2017-11-07 11:53:05 +00:00
|
|
|
});
|
|
|
|
object_ptr<FloatingIcon>(
|
|
|
|
result,
|
|
|
|
st::infoIconNotifications,
|
|
|
|
st::infoNotificationsIconPosition);
|
|
|
|
return std::move(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DetailsFiller::setupMainButtons() {
|
|
|
|
auto wrapButtons = [=](auto &&callback) {
|
|
|
|
auto topSkip = _wrap->add(CreateSlideSkipWidget(_wrap));
|
|
|
|
auto tracker = callback();
|
|
|
|
topSkip->toggleOn(std::move(tracker).atLeastOneShownValue());
|
|
|
|
};
|
|
|
|
if (auto user = _peer->asUser()) {
|
|
|
|
wrapButtons([=] {
|
|
|
|
return fillUserButtons(user);
|
|
|
|
});
|
|
|
|
} else if (auto channel = _peer->asChannel()) {
|
|
|
|
if (!channel->isMegagroup()) {
|
|
|
|
wrapButtons([=] {
|
|
|
|
return fillChannelButtons(channel);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ui::MultiSlideTracker DetailsFiller::fillUserButtons(
|
|
|
|
not_null<UserData*> user) {
|
|
|
|
using namespace rpl::mappers;
|
|
|
|
|
|
|
|
Ui::MultiSlideTracker tracker;
|
2017-12-09 15:13:06 +00:00
|
|
|
auto window = _controller->parentController();
|
2017-12-05 14:07:01 +00:00
|
|
|
|
|
|
|
auto addSendMessageButton = [&] {
|
2018-02-14 19:38:01 +00:00
|
|
|
auto activePeerValue = window->activeChatValue(
|
|
|
|
) | rpl::map([](Dialogs::Key key) {
|
|
|
|
return key.peer();
|
|
|
|
});
|
2017-12-05 14:07:01 +00:00
|
|
|
auto sendMessageVisible = rpl::combine(
|
|
|
|
_controller->wrapValue(),
|
2018-02-14 19:38:01 +00:00
|
|
|
std::move(activePeerValue),
|
2017-12-05 14:07:01 +00:00
|
|
|
(_1 != Wrap::Side) || (_2 != user));
|
|
|
|
auto sendMessage = [window, user] {
|
|
|
|
window->showPeerHistory(
|
|
|
|
user,
|
|
|
|
Window::SectionShow::Way::Forward);
|
|
|
|
};
|
|
|
|
AddMainButton(
|
|
|
|
_wrap,
|
|
|
|
Lang::Viewer(lng_profile_send_message),
|
|
|
|
std::move(sendMessageVisible),
|
|
|
|
std::move(sendMessage),
|
|
|
|
tracker);
|
2017-11-07 11:53:05 +00:00
|
|
|
};
|
|
|
|
|
2017-12-05 14:07:01 +00:00
|
|
|
if (user->isSelf()) {
|
|
|
|
auto separator = _wrap->add(object_ptr<Ui::SlideWrap<>>(
|
|
|
|
_wrap,
|
|
|
|
object_ptr<Ui::PlainShadow>(_wrap),
|
|
|
|
st::infoProfileSeparatorPadding)
|
|
|
|
)->setDuration(
|
|
|
|
st::infoSlideDuration
|
|
|
|
);
|
|
|
|
|
|
|
|
addSendMessageButton();
|
|
|
|
|
|
|
|
separator->toggleOn(
|
|
|
|
std::move(tracker).atLeastOneShownValue()
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
addSendMessageButton();
|
|
|
|
|
|
|
|
AddMainButton(
|
|
|
|
_wrap,
|
|
|
|
Lang::Viewer(lng_info_add_as_contact),
|
|
|
|
CanAddContactValue(user),
|
|
|
|
[user] { Window::PeerMenuAddContact(user); },
|
|
|
|
tracker);
|
|
|
|
}
|
2017-11-07 11:53:05 +00:00
|
|
|
return tracker;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ui::MultiSlideTracker DetailsFiller::fillChannelButtons(
|
|
|
|
not_null<ChannelData*> channel) {
|
|
|
|
using namespace rpl::mappers;
|
|
|
|
|
|
|
|
Ui::MultiSlideTracker tracker;
|
2017-12-09 15:13:06 +00:00
|
|
|
auto window = _controller->parentController();
|
2018-02-14 19:38:01 +00:00
|
|
|
auto activePeerValue = window->activeChatValue(
|
|
|
|
) | rpl::map([](Dialogs::Key key) {
|
|
|
|
return key.peer();
|
|
|
|
});
|
2017-11-17 17:02:49 +00:00
|
|
|
auto viewChannelVisible = rpl::combine(
|
|
|
|
_controller->wrapValue(),
|
2018-02-14 19:38:01 +00:00
|
|
|
std::move(activePeerValue),
|
2017-11-20 12:32:55 +00:00
|
|
|
(_1 != Wrap::Side) || (_2 != channel));
|
2017-11-07 11:53:05 +00:00
|
|
|
auto viewChannel = [=] {
|
|
|
|
window->showPeerHistory(
|
|
|
|
channel,
|
|
|
|
Window::SectionShow::Way::Forward);
|
|
|
|
};
|
|
|
|
AddMainButton(
|
|
|
|
_wrap,
|
|
|
|
Lang::Viewer(lng_profile_view_channel),
|
|
|
|
std::move(viewChannelVisible),
|
|
|
|
std::move(viewChannel),
|
|
|
|
tracker);
|
|
|
|
|
|
|
|
return tracker;
|
|
|
|
}
|
|
|
|
|
|
|
|
object_ptr<Ui::RpWidget> DetailsFiller::fill() {
|
|
|
|
add(object_ptr<BoxContentDivider>(_wrap));
|
|
|
|
add(CreateSkipWidget(_wrap));
|
|
|
|
add(setupInfo());
|
2017-12-05 14:07:01 +00:00
|
|
|
if (!_peer->isSelf()) {
|
|
|
|
add(setupMuteToggle());
|
|
|
|
}
|
2017-11-07 11:53:05 +00:00
|
|
|
setupMainButtons();
|
|
|
|
add(CreateSkipWidget(_wrap));
|
|
|
|
return std::move(_wrap);
|
|
|
|
}
|
|
|
|
|
|
|
|
ActionsFiller::ActionsFiller(
|
|
|
|
not_null<Controller*> controller,
|
|
|
|
not_null<Ui::RpWidget*> parent,
|
|
|
|
not_null<PeerData*> peer)
|
|
|
|
: _controller(controller)
|
|
|
|
, _parent(parent)
|
|
|
|
, _peer(peer) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void ActionsFiller::addInviteToGroupAction(
|
|
|
|
not_null<UserData*> user) {
|
|
|
|
AddActionButton(
|
|
|
|
_wrap,
|
|
|
|
Lang::Viewer(lng_profile_invite_to_group),
|
|
|
|
CanInviteBotToGroupValue(user),
|
|
|
|
[user] { AddBotToGroupBoxController::Start(user); });
|
|
|
|
}
|
|
|
|
|
|
|
|
void ActionsFiller::addShareContactAction(not_null<UserData*> user) {
|
|
|
|
AddActionButton(
|
|
|
|
_wrap,
|
2017-11-07 13:13:41 +00:00
|
|
|
Lang::Viewer(lng_info_share_contact),
|
2017-11-07 11:53:05 +00:00
|
|
|
CanShareContactValue(user),
|
2017-11-07 13:13:41 +00:00
|
|
|
[user] { Window::PeerMenuShareContactBox(user); });
|
2017-11-07 11:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ActionsFiller::addEditContactAction(not_null<UserData*> user) {
|
|
|
|
AddActionButton(
|
|
|
|
_wrap,
|
|
|
|
Lang::Viewer(lng_info_edit_contact),
|
|
|
|
IsContactValue(user),
|
|
|
|
[user] { Ui::show(Box<AddContactBox>(user)); });
|
|
|
|
}
|
|
|
|
|
|
|
|
void ActionsFiller::addDeleteContactAction(
|
|
|
|
not_null<UserData*> user) {
|
|
|
|
AddActionButton(
|
|
|
|
_wrap,
|
2017-11-07 13:13:41 +00:00
|
|
|
Lang::Viewer(lng_info_delete_contact),
|
2017-11-07 11:53:05 +00:00
|
|
|
IsContactValue(user),
|
2017-11-07 13:13:41 +00:00
|
|
|
[user] { Window::PeerMenuDeleteContact(user); });
|
2017-11-07 11:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ActionsFiller::addClearHistoryAction(not_null<UserData*> user) {
|
|
|
|
AddActionButton(
|
|
|
|
_wrap,
|
|
|
|
Lang::Viewer(lng_profile_clear_history),
|
|
|
|
rpl::single(true),
|
2017-12-06 14:39:27 +00:00
|
|
|
Window::ClearHistoryHandler(user));
|
2017-11-07 11:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ActionsFiller::addDeleteConversationAction(
|
|
|
|
not_null<UserData*> user) {
|
|
|
|
AddActionButton(
|
|
|
|
_wrap,
|
|
|
|
Lang::Viewer(lng_profile_delete_conversation),
|
|
|
|
rpl::single(true),
|
2017-12-06 14:39:27 +00:00
|
|
|
Window::DeleteAndLeaveHandler(user));
|
2017-11-07 11:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ActionsFiller::addBotCommandActions(not_null<UserData*> user) {
|
|
|
|
auto findBotCommand = [user](const QString &command) {
|
|
|
|
if (!user->botInfo) {
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
for_const (auto &data, user->botInfo->commands) {
|
|
|
|
auto isSame = data.command.compare(
|
|
|
|
command,
|
|
|
|
Qt::CaseInsensitive) == 0;
|
|
|
|
if (isSame) {
|
|
|
|
return data.command;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return QString();
|
|
|
|
};
|
|
|
|
auto hasBotCommandValue = [=](const QString &command) {
|
|
|
|
return Notify::PeerUpdateValue(
|
|
|
|
user,
|
2017-12-22 07:05:20 +00:00
|
|
|
Notify::PeerUpdate::Flag::BotCommandsChanged
|
|
|
|
) | rpl::map([=] {
|
|
|
|
return !findBotCommand(command).isEmpty();
|
|
|
|
});
|
2017-11-07 11:53:05 +00:00
|
|
|
};
|
|
|
|
auto sendBotCommand = [=](const QString &command) {
|
|
|
|
auto original = findBotCommand(command);
|
|
|
|
if (!original.isEmpty()) {
|
|
|
|
Ui::showPeerHistory(user, ShowAtTheEndMsgId);
|
|
|
|
App::sendBotCommand(user, user, '/' + original);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
auto addBotCommand = [=](LangKey key, const QString &command) {
|
|
|
|
AddActionButton(
|
|
|
|
_wrap,
|
|
|
|
Lang::Viewer(key),
|
|
|
|
hasBotCommandValue(command),
|
|
|
|
[=] { sendBotCommand(command); });
|
|
|
|
};
|
|
|
|
addBotCommand(lng_profile_bot_help, qsl("help"));
|
|
|
|
addBotCommand(lng_profile_bot_settings, qsl("settings"));
|
2018-05-30 14:25:29 +00:00
|
|
|
addBotCommand(lng_profile_bot_privacy, qsl("privacy"));
|
2017-11-07 11:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ActionsFiller::addReportAction() {
|
2019-03-12 10:36:33 +00:00
|
|
|
const auto peer = _peer;
|
2017-11-07 11:53:05 +00:00
|
|
|
AddActionButton(
|
|
|
|
_wrap,
|
|
|
|
Lang::Viewer(lng_profile_report),
|
|
|
|
rpl::single(true),
|
2019-03-12 10:36:33 +00:00
|
|
|
[=] { Ui::show(Box<ReportBox>(peer)); },
|
2017-11-07 11:53:05 +00:00
|
|
|
st::infoBlockButton);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ActionsFiller::addBlockAction(not_null<UserData*> user) {
|
|
|
|
auto text = Notify::PeerUpdateValue(
|
|
|
|
user,
|
2017-12-22 07:05:20 +00:00
|
|
|
Notify::PeerUpdate::Flag::UserIsBlocked
|
|
|
|
) | rpl::map([user] {
|
|
|
|
switch (user->blockStatus()) {
|
|
|
|
case UserData::BlockStatus::Blocked:
|
2019-03-12 10:36:33 +00:00
|
|
|
return Lang::Viewer((user->isBot() && !user->isSupport())
|
2018-12-04 11:46:07 +00:00
|
|
|
? lng_profile_restart_bot
|
2017-12-22 07:05:20 +00:00
|
|
|
: lng_profile_unblock_user);
|
|
|
|
case UserData::BlockStatus::NotBlocked:
|
|
|
|
default:
|
2019-03-12 10:36:33 +00:00
|
|
|
return Lang::Viewer((user->isBot() && !user->isSupport())
|
2017-12-22 07:05:20 +00:00
|
|
|
? lng_profile_block_bot
|
|
|
|
: lng_profile_block_user);
|
|
|
|
}
|
|
|
|
}) | rpl::flatten_latest(
|
|
|
|
) | rpl::start_spawning(_wrap->lifetime());
|
2017-11-07 11:53:05 +00:00
|
|
|
|
2017-12-22 07:05:20 +00:00
|
|
|
auto toggleOn = rpl::duplicate(
|
|
|
|
text
|
|
|
|
) | rpl::map([](const QString &text) {
|
|
|
|
return !text.isEmpty();
|
|
|
|
});
|
2018-12-04 11:46:07 +00:00
|
|
|
auto callback = [=] {
|
2017-11-07 11:53:05 +00:00
|
|
|
if (user->isBlocked()) {
|
|
|
|
Auth().api().unblockUser(user);
|
2018-12-04 11:46:07 +00:00
|
|
|
if (user->botInfo) {
|
|
|
|
Ui::showPeerHistory(user, ShowAtUnreadMsgId);
|
|
|
|
}
|
2017-11-07 11:53:05 +00:00
|
|
|
} else {
|
|
|
|
Auth().api().blockUser(user);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
AddActionButton(
|
|
|
|
_wrap,
|
|
|
|
rpl::duplicate(text),
|
|
|
|
std::move(toggleOn),
|
|
|
|
std::move(callback),
|
|
|
|
st::infoBlockButton);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ActionsFiller::addLeaveChannelAction(
|
|
|
|
not_null<ChannelData*> channel) {
|
|
|
|
AddActionButton(
|
|
|
|
_wrap,
|
|
|
|
Lang::Viewer(lng_profile_leave_channel),
|
|
|
|
AmInChannelValue(channel),
|
2018-02-08 09:20:14 +00:00
|
|
|
Window::DeleteAndLeaveHandler(channel));
|
2017-11-07 11:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ActionsFiller::addJoinChannelAction(
|
|
|
|
not_null<ChannelData*> channel) {
|
|
|
|
using namespace rpl::mappers;
|
|
|
|
auto joinVisible = AmInChannelValue(channel)
|
2017-11-20 12:32:55 +00:00
|
|
|
| rpl::map(!_1)
|
2017-11-07 11:53:05 +00:00
|
|
|
| rpl::start_spawning(_wrap->lifetime());
|
|
|
|
AddActionButton(
|
|
|
|
_wrap,
|
|
|
|
Lang::Viewer(lng_profile_join_channel),
|
|
|
|
rpl::duplicate(joinVisible),
|
|
|
|
[channel] { Auth().api().joinChannel(channel); });
|
|
|
|
_wrap->add(object_ptr<Ui::SlideWrap<Ui::FixedHeightWidget>>(
|
|
|
|
_wrap,
|
|
|
|
CreateSkipWidget(
|
|
|
|
_wrap,
|
|
|
|
st::infoBlockButtonSkip))
|
2017-11-19 11:37:15 +00:00
|
|
|
)->setDuration(
|
|
|
|
st::infoSlideDuration
|
|
|
|
)->toggleOn(
|
|
|
|
rpl::duplicate(joinVisible)
|
|
|
|
);
|
2017-11-07 11:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ActionsFiller::fillUserActions(not_null<UserData*> user) {
|
|
|
|
if (user->botInfo) {
|
|
|
|
addInviteToGroupAction(user);
|
|
|
|
}
|
|
|
|
addShareContactAction(user);
|
2017-12-05 14:07:01 +00:00
|
|
|
if (!user->isSelf()) {
|
|
|
|
addEditContactAction(user);
|
|
|
|
addDeleteContactAction(user);
|
|
|
|
}
|
2017-11-07 11:53:05 +00:00
|
|
|
addClearHistoryAction(user);
|
|
|
|
addDeleteConversationAction(user);
|
|
|
|
if (!user->isSelf()) {
|
|
|
|
if (user->botInfo) {
|
|
|
|
addBotCommandActions(user);
|
|
|
|
}
|
|
|
|
_wrap->add(CreateSkipWidget(
|
|
|
|
_wrap,
|
|
|
|
st::infoBlockButtonSkip));
|
2019-03-12 10:36:33 +00:00
|
|
|
if (user->isBot() && !user->isSupport()) {
|
2017-11-07 11:53:05 +00:00
|
|
|
addReportAction();
|
|
|
|
}
|
|
|
|
addBlockAction(user);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ActionsFiller::fillChannelActions(
|
|
|
|
not_null<ChannelData*> channel) {
|
|
|
|
using namespace rpl::mappers;
|
|
|
|
|
|
|
|
addJoinChannelAction(channel);
|
2017-11-10 19:19:43 +00:00
|
|
|
addLeaveChannelAction(channel);
|
2017-11-07 11:53:05 +00:00
|
|
|
if (!channel->amCreator()) {
|
|
|
|
addReportAction();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object_ptr<Ui::RpWidget> ActionsFiller::fill() {
|
|
|
|
auto wrapResult = [=](auto &&callback) {
|
|
|
|
_wrap = object_ptr<Ui::VerticalLayout>(_parent);
|
|
|
|
_wrap->add(CreateSkipWidget(_wrap));
|
|
|
|
callback();
|
|
|
|
_wrap->add(CreateSkipWidget(_wrap));
|
|
|
|
object_ptr<FloatingIcon>(
|
|
|
|
_wrap,
|
|
|
|
st::infoIconActions,
|
|
|
|
st::infoIconPosition);
|
|
|
|
return std::move(_wrap);
|
|
|
|
};
|
|
|
|
if (auto user = _peer->asUser()) {
|
|
|
|
return wrapResult([=] {
|
|
|
|
fillUserActions(user);
|
|
|
|
});
|
|
|
|
} else if (auto channel = _peer->asChannel()) {
|
2017-11-10 19:19:43 +00:00
|
|
|
if (channel->isMegagroup()) {
|
|
|
|
return { nullptr };
|
2017-11-07 11:53:05 +00:00
|
|
|
}
|
2017-11-10 19:19:43 +00:00
|
|
|
return wrapResult([=] {
|
|
|
|
fillChannelActions(channel);
|
|
|
|
});
|
2017-11-07 11:53:05 +00:00
|
|
|
}
|
|
|
|
return { nullptr };
|
|
|
|
}
|
|
|
|
|
2018-02-07 12:40:37 +00:00
|
|
|
FeedDetailsFiller::FeedDetailsFiller(
|
|
|
|
not_null<Controller*> controller,
|
|
|
|
not_null<Ui::RpWidget*> parent,
|
|
|
|
not_null<Data::Feed*> feed)
|
|
|
|
: _controller(controller)
|
|
|
|
, _parent(parent)
|
|
|
|
, _feed(feed)
|
|
|
|
, _wrap(_parent) {
|
|
|
|
}
|
|
|
|
|
|
|
|
object_ptr<Ui::RpWidget> FeedDetailsFiller::fill() {
|
|
|
|
add(object_ptr<BoxContentDivider>(_wrap));
|
|
|
|
add(CreateSkipWidget(_wrap));
|
|
|
|
add(setupDefaultToggle());
|
|
|
|
add(CreateSkipWidget(_wrap));
|
|
|
|
return std::move(_wrap);
|
|
|
|
}
|
|
|
|
|
|
|
|
object_ptr<Ui::RpWidget> FeedDetailsFiller::setupDefaultToggle() {
|
2018-02-08 09:20:14 +00:00
|
|
|
using namespace rpl::mappers;
|
|
|
|
const auto feedId = _feed->id();
|
2018-02-07 12:40:37 +00:00
|
|
|
auto result = object_ptr<Button>(
|
|
|
|
_wrap,
|
|
|
|
Lang::Viewer(lng_info_feed_is_default),
|
|
|
|
st::infoNotificationsButton);
|
|
|
|
result->toggleOn(
|
2018-02-08 09:20:14 +00:00
|
|
|
Auth().data().defaultFeedIdValue(
|
|
|
|
) | rpl::map(_1 == feedId)
|
2018-02-07 12:40:37 +00:00
|
|
|
)->addClickHandler([=] {
|
2018-02-08 09:20:14 +00:00
|
|
|
const auto makeDefault = (Auth().data().defaultFeedId() != feedId);
|
|
|
|
const auto defaultFeedId = makeDefault ? feedId : 0;
|
|
|
|
Auth().data().setDefaultFeedId(defaultFeedId);
|
2018-03-06 17:07:42 +00:00
|
|
|
// Auth().api().saveDefaultFeedId(feedId, makeDefault); // #feed
|
2018-02-07 12:40:37 +00:00
|
|
|
});
|
|
|
|
object_ptr<FloatingIcon>(
|
|
|
|
result,
|
|
|
|
st::infoIconNotifications,
|
|
|
|
st::infoNotificationsIconPosition);
|
|
|
|
return std::move(result);
|
|
|
|
}
|
|
|
|
|
2017-11-07 11:53:05 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
object_ptr<Ui::RpWidget> SetupDetails(
|
|
|
|
not_null<Controller*> controller,
|
|
|
|
not_null<Ui::RpWidget*> parent,
|
|
|
|
not_null<PeerData*> peer) {
|
|
|
|
DetailsFiller filler(controller, parent, peer);
|
|
|
|
return filler.fill();
|
|
|
|
}
|
|
|
|
|
|
|
|
object_ptr<Ui::RpWidget> SetupActions(
|
|
|
|
not_null<Controller*> controller,
|
|
|
|
not_null<Ui::RpWidget*> parent,
|
|
|
|
not_null<PeerData*> peer) {
|
|
|
|
ActionsFiller filler(controller, parent, peer);
|
|
|
|
return filler.fill();
|
|
|
|
}
|
|
|
|
|
2017-11-17 16:06:20 +00:00
|
|
|
void SetupAddChannelMember(
|
|
|
|
not_null<Ui::RpWidget*> parent,
|
|
|
|
not_null<ChannelData*> channel) {
|
|
|
|
auto add = Ui::CreateChild<Ui::IconButton>(
|
|
|
|
parent.get(),
|
|
|
|
st::infoMembersAddMember);
|
|
|
|
add->showOn(CanAddMemberValue(channel));
|
|
|
|
add->addClickHandler([channel] {
|
2017-11-19 14:41:52 +00:00
|
|
|
Window::PeerMenuAddChannelMembers(channel);
|
2017-11-17 16:06:20 +00:00
|
|
|
});
|
2017-12-22 07:05:20 +00:00
|
|
|
parent->widthValue(
|
|
|
|
) | rpl::start_with_next([add](int newWidth) {
|
|
|
|
auto availableWidth = newWidth
|
|
|
|
- st::infoMembersButtonPosition.x();
|
|
|
|
add->moveToLeft(
|
|
|
|
availableWidth - add->width(),
|
|
|
|
st::infoMembersButtonPosition.y(),
|
|
|
|
newWidth);
|
|
|
|
}, add->lifetime());
|
2017-11-17 16:06:20 +00:00
|
|
|
}
|
|
|
|
|
2017-11-10 19:19:43 +00:00
|
|
|
object_ptr<Ui::RpWidget> SetupChannelMembers(
|
|
|
|
not_null<Controller*> controller,
|
|
|
|
not_null<Ui::RpWidget*> parent,
|
|
|
|
not_null<PeerData*> peer) {
|
|
|
|
using namespace rpl::mappers;
|
|
|
|
|
|
|
|
auto channel = peer->asChannel();
|
|
|
|
if (!channel || channel->isMegagroup()) {
|
|
|
|
return { nullptr };
|
|
|
|
}
|
|
|
|
|
|
|
|
auto membersShown = rpl::combine(
|
|
|
|
MembersCountValue(channel),
|
|
|
|
Data::PeerFullFlagValue(
|
|
|
|
channel,
|
|
|
|
MTPDchannelFull::Flag::f_can_view_participants),
|
2017-11-20 12:32:55 +00:00
|
|
|
(_1 > 0) && _2);
|
2017-12-22 07:05:20 +00:00
|
|
|
auto membersText = MembersCountValue(
|
|
|
|
channel
|
|
|
|
) | rpl::map([](int count) {
|
2017-11-10 19:19:43 +00:00
|
|
|
return lng_chat_status_members(lt_count, count);
|
|
|
|
});
|
|
|
|
auto membersCallback = [controller, channel] {
|
2017-12-04 11:45:15 +00:00
|
|
|
controller->showSection(Info::Memento(
|
2017-11-17 16:06:20 +00:00
|
|
|
channel->id,
|
|
|
|
Section::Type::Members));
|
2017-11-10 19:19:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
auto result = object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
|
|
|
parent,
|
|
|
|
object_ptr<Ui::VerticalLayout>(parent));
|
2017-11-19 11:37:15 +00:00
|
|
|
result->setDuration(
|
|
|
|
st::infoSlideDuration
|
|
|
|
)->toggleOn(
|
|
|
|
std::move(membersShown)
|
|
|
|
);
|
2017-11-10 19:19:43 +00:00
|
|
|
|
|
|
|
auto members = result->entity();
|
|
|
|
members->add(object_ptr<BoxContentDivider>(members));
|
|
|
|
members->add(CreateSkipWidget(members));
|
2017-11-17 16:06:20 +00:00
|
|
|
auto button = AddActionButton(
|
2017-11-10 19:19:43 +00:00
|
|
|
members,
|
|
|
|
std::move(membersText),
|
|
|
|
rpl::single(true),
|
2017-11-17 16:06:20 +00:00
|
|
|
std::move(membersCallback))->entity();
|
|
|
|
|
|
|
|
SetupAddChannelMember(button, channel);
|
|
|
|
|
2017-11-10 19:19:43 +00:00
|
|
|
object_ptr<FloatingIcon>(
|
|
|
|
members,
|
|
|
|
st::infoIconMembers,
|
|
|
|
st::infoChannelMembersIconPosition);
|
|
|
|
members->add(CreateSkipWidget(members));
|
|
|
|
|
|
|
|
return std::move(result);
|
|
|
|
}
|
|
|
|
|
2018-02-07 12:40:37 +00:00
|
|
|
object_ptr<Ui::RpWidget> SetupFeedDetails(
|
|
|
|
not_null<Controller*> controller,
|
|
|
|
not_null<Ui::RpWidget*> parent,
|
|
|
|
not_null<Data::Feed*> feed) {
|
|
|
|
FeedDetailsFiller filler(controller, parent, feed);
|
|
|
|
return filler.fill();
|
|
|
|
}
|
|
|
|
|
2017-11-07 11:53:05 +00:00
|
|
|
} // namespace Profile
|
|
|
|
} // namespace Info
|