tdesktop/Telegram/SourceFiles/profile/profile_actions_widget.cpp

367 lines
11 KiB
C++

/*
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-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "profile/profile_actions_widget.h"
#include "styles/style_profile.h"
#include "ui/buttons/left_outline_button.h"
#include "boxes/confirmbox.h"
#include "boxes/report_box.h"
#include "mainwidget.h"
#include "observer_peer.h"
#include "apiwrap.h"
#include "lang.h"
namespace Profile {
using UpdateFlag = Notify::PeerUpdate::Flag;
ActionsWidget::ActionsWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_actions_section)) {
auto observeEvents = UpdateFlag::ChannelAmIn
| UpdateFlag::UserIsBlocked
| UpdateFlag::BotCommandsChanged
| UpdateFlag::MembersChanged;
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdated(update);
}));
validateBlockStatus();
refreshButtons();
}
void ActionsWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) {
if (update.peer != peer()) {
return;
}
auto needFullRefresh = [&update, this]() {
if (update.flags & UpdateFlag::BotCommandsChanged) {
if (_hasBotHelp != hasBotCommand(qsl("help")) || _hasBotSettings != hasBotCommand(qsl("settings"))) {
return true;
}
}
return false;
};
if (needFullRefresh()) {
refreshButtons();
} else {
if (update.flags & UpdateFlag::MembersChanged) {
refreshDeleteChannel();
}
if (update.flags & UpdateFlag::ChannelAmIn) {
refreshLeaveChannel();
}
if (update.flags & UpdateFlag::UserIsBlocked) {
refreshBlockUser();
}
refreshVisibility();
}
contentSizeUpdated();
}
void ActionsWidget::validateBlockStatus() const {
auto needFullPeer = [this]() {
if (auto user = peer()->asUser()) {
if (user->blockStatus() == UserData::BlockStatus::Unknown) {
return true;
} else if (user->botInfo && !user->botInfo->inited) {
return true;
}
}
return false;
};
if (needFullPeer()) {
if (App::api()) App::api()->requestFullPeer(peer());
}
}
Ui::LeftOutlineButton *ActionsWidget::addButton(const QString &text, const char *slot, const style::OutlineButton &st, int skipHeight) {
auto result = new Ui::LeftOutlineButton(this, text, st);
connect(result, SIGNAL(clicked()), this, slot);
result->show();
int top = buttonsBottom() + skipHeight;
resizeButton(result, width(), top);
_buttons.push_back(result);
return result;
};
void ActionsWidget::resizeButton(Ui::LeftOutlineButton *button, int newWidth, int top) {
int left = defaultOutlineButtonLeft();
int availableWidth = newWidth - left - st::profileBlockMarginRight;
accumulate_min(availableWidth, st::profileBlockOneLineWidthMax);
button->resizeToWidth(availableWidth);
button->moveToLeft(left, top);
}
void ActionsWidget::refreshButtons() {
auto buttons = createAndSwap(_buttons);
for_const (auto &button, buttons) {
delete button;
}
_blockUser = _leaveChannel = nullptr;
if (auto user = peer()->asUser()) {
if ((_hasBotHelp = hasBotCommand(qsl("help")))) {
addButton(lang(lng_profile_bot_help), SLOT(onBotHelp()));
}
if ((_hasBotSettings = hasBotCommand(qsl("settings")))) {
addButton(lang(lng_profile_bot_settings), SLOT(onBotSettings()));
}
addButton(lang(lng_profile_clear_history), SLOT(onClearHistory()));
addButton(lang(lng_profile_delete_conversation), SLOT(onDeleteConversation()));
refreshBlockUser();
} else if (auto chat = peer()->asChat()) {
if (chat->amCreator()) {
addButton(lang(lng_profile_migrate_button), SLOT(onUpgradeToSupergroup()));
}
addButton(lang(lng_profile_clear_history), SLOT(onClearHistory()));
addButton(lang(lng_profile_clear_and_exit), SLOT(onDeleteConversation()));
} else if (auto channel = peer()->asChannel()) {
if (!channel->amCreator()) {
addButton(lang(lng_profile_report), SLOT(onReport()));
}
refreshDeleteChannel();
refreshLeaveChannel();
}
refreshVisibility();
}
void ActionsWidget::refreshVisibility() {
setVisible(!_buttons.isEmpty());
}
QString ActionsWidget::getBlockButtonText() const {
auto user = peer()->asUser();
if (!user || (user->id == peerFromUser(MTP::authedId()))) return QString();
if (user->blockStatus() == UserData::BlockStatus::Unknown) return QString();
if (user->isBlocked()) {
if (user->botInfo) {
return lang(lng_profile_unblock_bot);
}
return lang(lng_profile_unblock_user);
} else if (user->botInfo) {
return lang(lng_profile_block_bot);
}
return lang(lng_profile_block_user);
}
bool ActionsWidget::hasBotCommand(const QString &command) const {
auto user = peer()->asUser();
if (!user || !user->botInfo || user->botInfo->commands.isEmpty()) {
return false;
}
for_const (auto &cmd, user->botInfo->commands) {
if (!cmd.command.compare(command, Qt::CaseInsensitive)) {
return true;
}
}
return false;
}
void ActionsWidget::sendBotCommand(const QString &command) {
auto user = peer()->asUser();
if (user && user->botInfo && !user->botInfo->commands.isEmpty()) {
for_const (auto &cmd, user->botInfo->commands) {
if (!cmd.command.compare(command, Qt::CaseInsensitive)) {
Ui::showPeerHistory(user, ShowAtTheEndMsgId);
App::sendBotCommand(user, user, '/' + cmd.command);
return;
}
}
}
// Command was not found.
refreshButtons();
contentSizeUpdated();
}
void ActionsWidget::refreshBlockUser() {
if (auto user = peer()->asUser()) {
auto blockText = getBlockButtonText();
if (_blockUser) {
if (blockText.isEmpty()) {
_buttons.removeOne(_blockUser);
delete _blockUser;
_blockUser = nullptr;
} else {
_blockUser->setText(blockText);
}
} else if (!blockText.isEmpty()) {
_blockUser = addButton(blockText, SLOT(onBlockUser()), st::attentionLeftOutlineButton, st::profileBlockOneLineSkip);
}
}
}
void ActionsWidget::refreshDeleteChannel() {
if (auto channel = peer()->asChannel()) {
if (channel->canDelete() && !_deleteChannel) {
_deleteChannel = addButton(lang(channel->isMegagroup() ? lng_profile_delete_group : lng_profile_delete_channel), SLOT(onDeleteChannel()), st::attentionLeftOutlineButton);
} else if (!channel->canDelete() && _deleteChannel) {
_buttons.removeOne(_deleteChannel);
delete _deleteChannel;
_deleteChannel = nullptr;
}
}
}
void ActionsWidget::refreshLeaveChannel() {
if (auto channel = peer()->asChannel()) {
if (!channel->amCreator()) {
if (channel->amIn() && !_leaveChannel) {
_leaveChannel = addButton(lang(channel->isMegagroup() ? lng_profile_leave_group : lng_profile_leave_channel), SLOT(onLeaveChannel()));
} else if (!channel->amIn() && _leaveChannel) {
_buttons.removeOne(_leaveChannel);
delete _leaveChannel;
_leaveChannel = nullptr;
}
}
}
}
int ActionsWidget::resizeGetHeight(int newWidth) {
for_const (auto button, _buttons) {
resizeButton(button, newWidth, button->y());
}
return buttonsBottom();
}
int ActionsWidget::buttonsBottom() const {
if (_buttons.isEmpty()) {
return contentTop();
}
auto lastButton = _buttons.back();
return lastButton->y() + lastButton->height();
}
void ActionsWidget::onBotHelp() {
sendBotCommand(qsl("help"));
}
void ActionsWidget::onBotSettings() {
sendBotCommand(qsl("settings"));
}
void ActionsWidget::onClearHistory() {
QString confirmation;
if (auto user = peer()->asUser()) {
confirmation = lng_sure_delete_history(lt_contact, App::peerName(peer()));
} else if (auto chat = peer()->asChat()) {
confirmation = lng_sure_delete_group_history(lt_group, App::peerName(peer()));
}
if (!confirmation.isEmpty()) {
auto box = new ConfirmBox(confirmation, lang(lng_box_delete), st::attentionBoxButton);
connect(box, SIGNAL(confirmed()), this, SLOT(onClearHistorySure()));
Ui::showLayer(box);
}
}
void ActionsWidget::onClearHistorySure() {
Ui::hideLayer();
App::main()->clearHistory(peer());
Ui::showPeerHistory(peer(), ShowAtUnreadMsgId);
}
void ActionsWidget::onDeleteConversation() {
QString confirmation, confirmButton;
if (auto user = peer()->asUser()) {
confirmation = lng_sure_delete_history(lt_contact, App::peerName(peer()));
confirmButton = lang(lng_box_delete);
} else if (auto chat = peer()->asChat()) {
confirmation = lng_sure_delete_and_exit(lt_group, App::peerName(peer()));
confirmButton = lang(lng_box_leave);
}
if (!confirmation.isEmpty()) {
auto box = new ConfirmBox(confirmation, confirmButton, st::attentionBoxButton);
connect(box, SIGNAL(confirmed()), this, SLOT(onDeleteConversationSure()));
Ui::showLayer(box);
}
}
void ActionsWidget::onDeleteConversationSure() {
Ui::hideLayer();
Ui::showChatsList();
if (auto user = peer()->asUser()) {
App::main()->deleteConversation(peer());
} else if (auto chat = peer()->asChat()) {
App::main()->deleteAndExit(chat);
}
}
void ActionsWidget::onBlockUser() {
if (auto user = peer()->asUser()) {
if (user->isBlocked()) {
App::api()->unblockUser(user);
} else {
App::api()->blockUser(user);
}
}
}
void ActionsWidget::onUpgradeToSupergroup() {
if (auto chat = peer()->asChat()) {
Ui::showLayer(new ConvertToSupergroupBox(chat));
}
}
void ActionsWidget::onDeleteChannel() {
auto box = new ConfirmBox(lang(peer()->isMegagroup() ? lng_sure_delete_group : lng_sure_delete_channel), lang(lng_box_delete), st::attentionBoxButton);
connect(box, SIGNAL(confirmed()), this, SLOT(onDeleteChannelSure()));
Ui::showLayer(box);
}
void ActionsWidget::onDeleteChannelSure() {
Ui::hideLayer();
Ui::showChatsList();
if (auto chat = peer()->migrateFrom()) {
App::main()->deleteAndExit(chat);
}
if (auto channel = peer()->asChannel()) {
MTP::send(MTPchannels_DeleteChannel(channel->inputChannel), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::deleteChannelFailed));
}
}
void ActionsWidget::onLeaveChannel() {
auto channel = peer()->asChannel();
if (!channel) return;
auto box = new ConfirmBox(lang(channel->isMegagroup() ? lng_sure_leave_group : lng_sure_leave_channel), lang(lng_box_leave));
connect(box, SIGNAL(confirmed()), this, SLOT(onLeaveChannelSure()));
Ui::showLayer(box);
}
void ActionsWidget::onLeaveChannelSure() {
App::api()->leaveChannel(peer()->asChannel());
}
void ActionsWidget::onReport() {
if (auto channel = peer()->asChannel()) {
Ui::showLayer(new ReportBox(channel));
}
}
} // namespace Profile