From dd3ae22e08b2de8f9abd4fc391c7fa5cb51f4e6f Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 10 Nov 2017 21:15:37 +0400 Subject: [PATCH] Save data from EditPeerInfoBox. --- Telegram/SourceFiles/boxes/abstract_box.cpp | 6 + Telegram/SourceFiles/boxes/abstract_box.h | 2 + .../boxes/peers/edit_peer_info_box.cpp | 266 +++++++++++++++++- .../SourceFiles/ui/widgets/scroll_area.cpp | 10 + Telegram/SourceFiles/ui/widgets/scroll_area.h | 1 + 5 files changed, 282 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/boxes/abstract_box.cpp b/Telegram/SourceFiles/boxes/abstract_box.cpp index 817f524cd..0c46ecedf 100644 --- a/Telegram/SourceFiles/boxes/abstract_box.cpp +++ b/Telegram/SourceFiles/boxes/abstract_box.cpp @@ -84,6 +84,12 @@ void BoxContent::finishScrollCreate() { connect(_scroll, SIGNAL(innerResized()), this, SLOT(onInnerResize())); } +void BoxContent::scrollToWidget(not_null widget) { + if (_scroll) { + _scroll->scrollToWidget(widget); + } +} + void BoxContent::onScrollToY(int top, int bottom) { if (_scroll) { _scroll->scrollToY(top, bottom); diff --git a/Telegram/SourceFiles/boxes/abstract_box.h b/Telegram/SourceFiles/boxes/abstract_box.h index 07d0fb7c3..5b9454598 100644 --- a/Telegram/SourceFiles/boxes/abstract_box.h +++ b/Telegram/SourceFiles/boxes/abstract_box.h @@ -89,6 +89,8 @@ public: getDelegate()->setAdditionalTitle(std::move(additional)); } + void scrollToWidget(not_null widget); + void clearButtons() { getDelegate()->clearButtons(); } diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp index 73ab6061f..d16266b4f 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp @@ -93,6 +93,13 @@ private: std::shared_ptr> invites; Ui::Checkbox *signatures = nullptr; }; + struct Saving { + base::optional username; + base::optional title; + base::optional description; + base::optional signatures; + base::optional everyoneInvites; + }; base::lambda computeTitle() const; object_ptr createPhotoAndTitleEdit(); @@ -110,7 +117,6 @@ private: void refreshInitialPhotoImage(); void submitTitle(); void submitDescription(); - void save(); void deleteWithConfirmation(); void choosePhotoDelayed(); void choosePhoto(); @@ -136,6 +142,23 @@ private: void revokeInviteLink(); void exportInviteLink(const QString &confirmation); + base::optional validate() const; + bool validateUsername(Saving &to) const; + bool validateTitle(Saving &to) const; + bool validateDescription(Saving &to) const; + bool validateInvites(Saving &to) const; + bool validateSignatures(Saving &to) const; + + void save(); + void saveUsername(); + void saveTitle(); + void saveDescription(); + void saveInvites(); + void saveSignatures(); + void pushSaveStage(base::lambda_once &&lambda); + void continueSave(); + void cancelSave(); + not_null _box; not_null _channel; bool _isGroup; @@ -147,6 +170,9 @@ private: UsernameState _usernameState = UsernameState::Normal; rpl::event_stream> _usernameResultTexts; + std::deque> _saveStagesQueue; + Saving _savingData; + }; Controller::Controller( @@ -453,6 +479,7 @@ void Controller::privacyChanged(Privacy value) { refreshVisibilities(); _controls.username->setDisplayFocused(true); _controls.username->setFocus(); + _box->scrollToWidget(_controls.username); } else { request(base::take(_checkUsernameRequestId)).cancel(); _checkUsernameTimer.cancel(); @@ -496,7 +523,7 @@ void Controller::checkUsernameAvailability() { if (type == qstr("CHANNEL_PUBLIC_GROUP_NA")) { _usernameState = UsernameState::NotAvailable; _controls.privacy->setValue(Privacy::Private); - } else if (rand() % 10 < 2 || type == qstr("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) { + } else if (type == qstr("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) { _usernameState = UsernameState::TooMany; if (_controls.privacy->value() == Privacy::Public) { askUsernameRevoke(); @@ -505,6 +532,7 @@ void Controller::checkUsernameAvailability() { if (_controls.privacy->value() == Privacy::Public) { _controls.usernameResult = nullptr; _controls.username->setFocus(); + _box->scrollToWidget(_controls.username); } } else if (type == qstr("USERNAME_INVALID")) { showUsernameError( @@ -840,8 +868,10 @@ void Controller::submitTitle() { if (_controls.title->getLastText().isEmpty()) { _controls.title->showError(); + _box->scrollToWidget(_controls.title); } else { _controls.description->setFocus(); + _box->scrollToWidget(_controls.description); } } @@ -851,15 +881,245 @@ void Controller::submitDescription() { if (_controls.title->getLastText().isEmpty()) { _controls.title->showError(); - _controls.title->setFocus(); + _box->scrollToWidget(_controls.title); } else { save(); } } +base::optional Controller::validate() const { + auto result = Saving(); + if (validateUsername(result) + && validateTitle(result) + && validateDescription(result) + && validateInvites(result) + && validateSignatures(result)) { + return result; + } + return {}; +} + +bool Controller::validateUsername(Saving &to) const { + if (!_controls.privacy) { + return true; + } else if (_controls.privacy->value() == Privacy::Private) { + to.username = QString(); + return true; + } + auto username = _controls.username->getLastText().trimmed(); + if (username.isEmpty()) { + _controls.username->showError(); + _box->scrollToWidget(_controls.username); + return false; + } + to.username = username; + return true; +} + +bool Controller::validateTitle(Saving &to) const { + if (!_controls.title) { + return true; + } + auto title = _controls.title->getLastText().trimmed(); + if (title.isEmpty()) { + _controls.title->showError(); + _box->scrollToWidget(_controls.title); + return false; + } + to.title = title; + return true; +} + +bool Controller::validateDescription(Saving &to) const { + if (!_controls.description) { + return true; + } + to.description = _controls.description->getLastText().trimmed(); + return true; +} + +bool Controller::validateInvites(Saving &to) const { + if (!_controls.invites) { + return true; + } + to.everyoneInvites + = (_controls.invites->value() == Invites::Everyone); + return true; +} + +bool Controller::validateSignatures(Saving &to) const { + if (!_controls.signatures) { + return true; + } + to.signatures = _controls.signatures->checked(); + return true; +} + void Controller::save() { Expects(_wrap != nullptr); + if (!_saveStagesQueue.empty()) { + return; + } + if (auto saving = validate()) { + _savingData = *saving; + pushSaveStage([this] { saveUsername(); }); + pushSaveStage([this] { saveTitle(); }); + pushSaveStage([this] { saveDescription(); }); + pushSaveStage([this] { saveInvites(); }); + pushSaveStage([this] { saveSignatures(); }); + pushSaveStage([this] { _box->closeBox(); }); + continueSave(); + } +} + +void Controller::pushSaveStage(base::lambda_once &&lambda) { + _saveStagesQueue.push_back(std::move(lambda)); +} + +void Controller::continueSave() { + if (!_saveStagesQueue.empty()) { + auto next = std::move(_saveStagesQueue.front()); + _saveStagesQueue.pop_front(); + next(); + } +} + +void Controller::cancelSave() { + _saveStagesQueue.clear(); +} + +void Controller::saveUsername() { + if (!_savingData.username + || *_savingData.username == _channel->username) { + return continueSave(); + } + request(MTPchannels_UpdateUsername( + _channel->inputChannel, + MTP_string(*_savingData.username) + )).done([this](const MTPBool &result) { + _channel->setName( + TextUtilities::SingleLine(_channel->name), + *_savingData.username); + continueSave(); + }).fail([this](const RPCError &error) { + auto type = error.type(); + if (type == qstr("USERNAME_NOT_MODIFIED")) { + _channel->setName( + TextUtilities::SingleLine(_channel->name), + TextUtilities::SingleLine(*_savingData.username)); + continueSave(); + return; + } + auto errorKey = [&] { + if (type == qstr("USERNAME_INVALID")) { + return lng_create_channel_link_invalid; + } else if (type == qstr("USERNAME_OCCUPIED") + || type == qstr("USERNAMES_UNAVAILABLE")) { + return lng_create_channel_link_invalid; + } + return lng_create_channel_link_invalid; + }(); + _controls.username->showError(); + _box->scrollToWidget(_controls.username); + showUsernameError(Lang::Viewer(errorKey)); + cancelSave(); + }).send(); +} + +void Controller::saveTitle() { + if (!_savingData.title || *_savingData.title == _channel->name) { + return continueSave(); + } + request(MTPchannels_EditTitle( + _channel->inputChannel, + MTP_string(*_savingData.title) + )).done([this](const MTPUpdates &result) { + Auth().api().applyUpdates(result); + continueSave(); + }).fail([this](const RPCError &error) { + auto type = error.type(); + if (type == qstr("CHAT_NOT_MODIFIED") + || type == qstr("CHAT_TITLE_NOT_MODIFIED")) { + _channel->setName(*_savingData.title, _channel->username); + continueSave(); + return; + } + if (type == qstr("NO_CHAT_TITLE")) { + _controls.title->showError(); + _box->scrollToWidget(_controls.title); + } else { + _controls.title->setFocus(); + } + cancelSave(); + }).send(); +} + +void Controller::saveDescription() { + if (!_savingData.description + || *_savingData.description == _channel->about()) { + return continueSave(); + } + auto successCallback = [this] { + if (_channel->setAbout(*_savingData.description)) { + Auth().api().fullPeerUpdated().notify(_channel); + } + continueSave(); + }; + request(MTPchannels_EditAbout( + _channel->inputChannel, + MTP_string(*_savingData.description) + )).done([=](const MTPBool &result) { + successCallback(); + }).fail([=](const RPCError &error) { + auto type = error.type(); + if (type == qstr("CHAT_ABOUT_NOT_MODIFIED")) { + successCallback(); + return; + } + _controls.description->setFocus(); + cancelSave(); + }).send(); +} + +void Controller::saveInvites() { + if (!_savingData.everyoneInvites + || *_savingData.everyoneInvites == _channel->anyoneCanAddMembers()) { + return continueSave(); + } + request(MTPchannels_ToggleInvites( + _channel->inputChannel, + MTP_bool(*_savingData.everyoneInvites) + )).done([this](const MTPUpdates &result) { + Auth().api().applyUpdates(result); + continueSave(); + }).fail([this](const RPCError &error) { + if (error.type() == qstr("CHAT_NOT_MODIFIED")) { + continueSave(); + } else { + cancelSave(); + } + }).send(); +} + +void Controller::saveSignatures() { + if (!_savingData.signatures + || *_savingData.signatures == _channel->addsSignature()) { + return continueSave(); + } + request(MTPchannels_ToggleSignatures( + _channel->inputChannel, + MTP_bool(*_savingData.signatures) + )).done([this](const MTPUpdates &result) { + Auth().api().applyUpdates(result); + continueSave(); + }).fail([this](const RPCError &error) { + if (error.type() == qstr("CHAT_NOT_MODIFIED")) { + continueSave(); + } else { + cancelSave(); + } + }).send(); } void Controller::deleteWithConfirmation() { diff --git a/Telegram/SourceFiles/ui/widgets/scroll_area.cpp b/Telegram/SourceFiles/ui/widgets/scroll_area.cpp index b13f0cff2..3929da625 100644 --- a/Telegram/SourceFiles/ui/widgets/scroll_area.cpp +++ b/Telegram/SourceFiles/ui/widgets/scroll_area.cpp @@ -689,6 +689,16 @@ void ScrollArea::scrollTo(ScrollToRequest request) { scrollToY(request.ymin, request.ymax); } +void ScrollArea::scrollToWidget(not_null widget) { + if (auto local = this->widget()) { + auto globalPosition = widget->mapToGlobal(QPoint(0, 0)); + auto localPosition = local->mapFromGlobal(globalPosition); + auto localTop = localPosition.y(); + auto localBottom = localTop + widget->height(); + scrollToY(localTop, localBottom); + } +} + void ScrollArea::scrollToY(int toTop, int toBottom) { myEnsureResized(widget()); myEnsureResized(this); diff --git a/Telegram/SourceFiles/ui/widgets/scroll_area.h b/Telegram/SourceFiles/ui/widgets/scroll_area.h index db7f0bf6a..1c30df3c2 100644 --- a/Telegram/SourceFiles/ui/widgets/scroll_area.h +++ b/Telegram/SourceFiles/ui/widgets/scroll_area.h @@ -219,6 +219,7 @@ public: } void scrollTo(ScrollToRequest request); + void scrollToWidget(not_null widget); protected: bool eventFilter(QObject *obj, QEvent *e) override;