Allow to edit Bio in Settings.

This commit is contained in:
John Preston 2017-07-18 18:15:02 +03:00
parent 9bd89121e8
commit 34d2e78308
13 changed files with 202 additions and 46 deletions

View File

@ -271,10 +271,15 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_username_link" = "This link opens a chat with you:";
"lng_username_copied" = "Link copied to clipboard.";
"lng_bio_title" = "Edit your bio";
"lng_bio_placeholder" = "Bio";
"lng_bio_about" = "You can add a few lines about yourself. Anyone who opens your profile will see this text.";
"lng_settings_section_info" = "Info";
"lng_settings_phone_number" = "Phone number:";
"lng_settings_username" = "Username:";
"lng_settings_choose_username" = "Choose username";
"lng_settings_empty_bio" = "None";
"lng_settings_section_notify" = "Notifications";
"lng_settings_desktop_notify" = "Desktop notifications";
@ -570,6 +575,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_profile_mobile_number" = "Mobile:";
"lng_profile_username" = "Username:";
"lng_profile_link" = "Link:";
"lng_profile_bio" = "Bio:";
"lng_profile_add_contact" = "Add Contact";
"lng_profile_edit_contact" = "Edit";
"lng_profile_enable_notifications" = "Notifications";

View File

@ -41,6 +41,20 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "observer_peer.h"
#include "auth_session.h"
namespace {
constexpr auto kMaxGroupChannelTitle = 255;
constexpr auto kMaxChannelDescription = 255;
constexpr auto kMaxBioLength = 70;
style::InputField CreateBioFieldStyle() {
auto result = st::newGroupDescription;
result.textMargins.setRight(st::boxTextFont->spacew + st::boxTextFont->width(QString::number(kMaxBioLength)));
return result;
}
} // namespace
class RevokePublicLinkBox::Inner : public TWidget, private MTP::Sender {
public:
Inner(QWidget *parent, base::lambda<void()> revokeCallback);
@ -290,12 +304,12 @@ GroupInfoBox::GroupInfoBox(QWidget*, CreatingGroupType creating, bool fromTypeCh
void GroupInfoBox::prepare() {
setMouseTracking(true);
_title->setMaxLength(MaxGroupChannelTitle);
_title->setMaxLength(kMaxGroupChannelTitle);
if (_creating == CreatingGroupChannel) {
_description.create(this, st::newGroupDescription, langFactory(lng_create_group_description));
_description->show();
_description->setMaxLength(MaxChannelDescription);
_description->setMaxLength(kMaxChannelDescription);
connect(_description, SIGNAL(resized()), this, SLOT(onDescriptionResized()));
connect(_description, SIGNAL(submitted(bool)), this, SLOT(onNext()));
@ -828,8 +842,8 @@ void EditNameTitleBox::prepare() {
if (_invertOrder) {
setTabOrder(_last, _first);
}
_first->setMaxLength(MaxGroupChannelTitle);
_last->setMaxLength(MaxGroupChannelTitle);
_first->setMaxLength(kMaxGroupChannelTitle);
_last->setMaxLength(kMaxGroupChannelTitle);
connect(_first, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
connect(_last, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
@ -960,6 +974,76 @@ void EditNameTitleBox::onSaveChatDone(const MTPUpdates &updates) {
closeBox();
}
EditBioBox::EditBioBox(QWidget*, gsl::not_null<UserData*> self) : BoxContent()
, _dynamicFieldStyle(CreateBioFieldStyle())
, _self(self)
, _bio(this, _dynamicFieldStyle, langFactory(lng_bio_placeholder), _self->about())
, _countdown(this, QString(), Ui::FlatLabel::InitType::Simple, st::editBioCountdownLabel)
, _about(this, lang(lng_bio_about), Ui::FlatLabel::InitType::Simple, st::aboutRevokePublicLabel) {
}
void EditBioBox::prepare() {
setTitle(langFactory(lng_bio_title));
addButton(langFactory(lng_settings_save), [this] { save(); });
addButton(langFactory(lng_cancel), [this] { closeBox(); });
_bio->setMaxLength(kMaxBioLength);
_bio->setCtrlEnterSubmit(Ui::CtrlEnterSubmit::Both);
auto cursor = _bio->textCursor();
cursor.setPosition(_bio->getLastText().size());
_bio->setTextCursor(cursor);
connect(_bio, &Ui::InputArea::submitted, this, [this](bool ctrlShiftEnter) { save(); });
connect(_bio, &Ui::InputArea::resized, this, [this] { updateMaxHeight(); });
connect(_bio, &Ui::InputArea::changed, this, [this] { handleBioUpdated(); });
handleBioUpdated();
updateMaxHeight();
}
void EditBioBox::updateMaxHeight() {
auto newHeight = st::contactPadding.top() + _bio->height() + st::boxLittleSkip + _about->height() + st::boxPadding.bottom() + st::contactPadding.bottom();
setDimensions(st::boxWideWidth, newHeight);
}
void EditBioBox::handleBioUpdated() {
auto text = _bio->getLastText();
if (text.indexOf('\n') >= 0) {
auto position = _bio->textCursor().position();
_bio->setText(text.replace('\n', ' '));
auto cursor = _bio->textCursor();
cursor.setPosition(position);
_bio->setTextCursor(cursor);
}
auto countLeft = qMax(kMaxBioLength - text.size(), 0);
_countdown->setText(QString::number(countLeft));
}
void EditBioBox::setInnerFocus() {
_bio->setFocusFast();
}
void EditBioBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_bio->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _bio->height());
_bio->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::contactPadding.top());
_countdown->moveToRight(st::boxPadding.right(), _bio->y() + _dynamicFieldStyle.textMargins.top());
_about->moveToLeft(st::boxPadding.left(), _bio->y() + _bio->height() + st::boxLittleSkip);
}
void EditBioBox::save() {
if (_requestId) return;
auto text = TextUtilities::PrepareForSending(_bio->getLastText());
_sentBio = text;
auto flags = MTPaccount_UpdateProfile::Flag::f_about;
_requestId = request(MTPaccount_UpdateProfile(MTP_flags(flags), MTPstring(), MTPstring(), MTP_string(text))).done([this](const MTPUser &result) {
App::feedUsers(MTP_vector<MTPUser>(1, result));
_self->setAbout(_sentBio);
closeBox();
}).send();
}
EditChannelBox::EditChannelBox(QWidget*, gsl::not_null<ChannelData*> channel)
: _channel(channel)
, _title(this, st::defaultInputField, langFactory(_channel->isMegagroup() ? lng_dlg_new_group_name : lng_dlg_new_channel_name), _channel->name)
@ -981,8 +1065,8 @@ void EditChannelBox::prepare() {
setMouseTracking(true);
_title->setMaxLength(MaxGroupChannelTitle);
_description->setMaxLength(MaxChannelDescription);
_title->setMaxLength(kMaxGroupChannelTitle);
_description->setMaxLength(kMaxChannelDescription);
connect(_description, SIGNAL(resized()), this, SLOT(onDescriptionResized()));
connect(_description, SIGNAL(submitted(bool)), this, SLOT(onSave()));

View File

@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#pragma once
#include "boxes/abstract_box.h"
#include "mtproto/sender.h"
class ConfirmBox;
@ -230,6 +231,32 @@ private:
};
class EditBioBox : public BoxContent, private MTP::Sender {
public:
EditBioBox(QWidget*, gsl::not_null<UserData*> self);
protected:
void setInnerFocus() override;
void prepare() override;
void resizeEvent(QResizeEvent *e) override;
private:
void updateMaxHeight();
void handleBioUpdated();
void save();
style::InputField _dynamicFieldStyle;
gsl::not_null<UserData*> _self;
object_ptr<Ui::InputArea> _bio;
object_ptr<Ui::FlatLabel> _countdown;
object_ptr<Ui::FlatLabel> _about;
mtpRequestId _requestId = 0;
QString _sentBio;
};
class EditChannelBox : public BoxContent, public RPCSender {
Q_OBJECT

View File

@ -202,6 +202,10 @@ aboutRevokePublicLabel: FlatLabel(defaultFlatLabel) {
align: align(topleft);
width: 320px;
}
editBioCountdownLabel: FlatLabel(defaultFlatLabel) {
style: boxTextStyle;
textFg: windowSubTextFg;
}
contactUserIcon: icon {{ "add_contact_user", menuIconFg }};
contactPhoneIcon: icon {{ "add_contact_phone", menuIconFg }};
@ -563,11 +567,7 @@ passcodeTextStyle: TextStyle(defaultTextStyle) {
usernamePadding: margins(23px, 6px, 21px, 12px);
usernameSkip: 49px;
usernameTextStyle: TextStyle(passcodeTextStyle) {
font: boxTextFont;
linkFont: boxTextFont;
linkFontOver: font(boxFontSize underline);
}
usernameTextStyle: boxTextStyle;
usernameDefaultFg: windowSubTextFg;
downloadPathSkip: 10px;

View File

@ -112,8 +112,6 @@ enum {
MaxUsernameLength = 32,
UsernameCheckTimeout = 200,
MaxChannelDescription = 255,
MaxGroupChannelTitle = 255,
MaxPhotoCaption = 200,
MaxMessageSize = 4096,

View File

@ -30,10 +30,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "ui/widgets/tooltip.h"
#include "core/file_utilities.h"
QString UrlClickHandler::copyToClipboardContextItemText() const {
return lang(isEmail() ? lng_context_copy_email : lng_context_copy_link);
}
namespace {
QString tryConvertUrlToLocal(QString url) {
@ -80,6 +76,24 @@ bool UrlRequiresConfirmation(const QUrl &url) {
} // namespace
QString UrlClickHandler::copyToClipboardContextItemText() const {
return lang(isEmail() ? lng_context_copy_email : lng_context_copy_link);
}
QString UrlClickHandler::url() const {
if (isEmail()) {
return _originalUrl;
}
QUrl u(_originalUrl), good(u.isValid() ? u.toEncoded() : QString());
QString result(good.isValid() ? QString::fromUtf8(good.toEncoded()) : _originalUrl);
if (!result.isEmpty() && !QRegularExpression(qsl("^[a-zA-Z]+:")).match(result).hasMatch()) { // no protocol
return qsl("http://") + result;
}
return result;
}
void UrlClickHandler::doOpen(QString url) {
Ui::Tooltip::Hide();

View File

@ -80,19 +80,7 @@ public:
}
protected:
QString url() const override {
if (isEmail()) {
return _originalUrl;
}
QUrl u(_originalUrl), good(u.isValid() ? u.toEncoded() : QString());
QString result(good.isValid() ? QString::fromUtf8(good.toEncoded()) : _originalUrl);
if (!QRegularExpression(qsl("^[a-zA-Z]+:")).match(result).hasMatch()) { // no protocol
return qsl("http://") + result;
}
return result;
}
QString url() const override;
QString readable() const override {
return _readable;
}
@ -115,6 +103,9 @@ class HiddenUrlClickHandler : public UrlClickHandler {
public:
HiddenUrlClickHandler(QString url) : UrlClickHandler(url, false) {
}
QString copyToClipboardContextItemText() const override {
return url().isEmpty() ? QString() : UrlClickHandler::copyToClipboardContextItemText();
}
static void doOpen(QString url);
void onClick(Qt::MouseButton button) const override {

View File

@ -29,6 +29,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "intro/introsignup.h"
#include "intro/intropwdcheck.h"
#include "mainwidget.h"
#include "apiwrap.h"
#include "mainwindow.h"
#include "messenger.h"
#include "application.h"
@ -455,6 +456,9 @@ void Widget::Step::finish(const MTPUser &user, QImage photo) {
App::wnd()->setupMain(&user);
// "this" is already deleted here by creating the main widget.
if (auto user = App::self()) {
App::api()->requestFullPeer(user);
}
if (!photo.isNull()) {
App::app()->uploadProfilePhoto(photo, AuthSession::CurrentUserId());
}

View File

@ -3995,7 +3995,7 @@ void MainWidget::mtpPing() {
void MainWidget::start(const MTPUser *self) {
if (!self) {
MTP::send(MTPusers_GetUsers(MTP_vector<MTPInputUser>(1, MTP_inputUserSelf())), rpcDone(&MainWidget::startWithSelf));
MTP::send(MTPusers_GetFullUser(MTP_inputUserSelf()), rpcDone(&MainWidget::startWithSelf));
return;
}
if (!AuthSession::Current().validateSelf(*self)) {
@ -4227,13 +4227,13 @@ bool MainWidget::inviteImportFail(const RPCError &error) {
return true;
}
void MainWidget::startWithSelf(const MTPVector<MTPUser> &users) {
auto &v = users.v;
if (v.isEmpty()) {
LOG(("Auth Error: self user not received."));
return App::logOutDelayed();
void MainWidget::startWithSelf(const MTPUserFull &result) {
Expects(result.type() == mtpc_userFull);
auto &d = result.c_userFull();
start(&d.vuser);
if (auto user = App::self()) {
App::api()->processFullPeer(user, result);
}
start(&v[0]);
}
void MainWidget::applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNotifySettings &settings, History *h) {

View File

@ -535,7 +535,7 @@ private:
Window::SectionSlideParams prepareOverviewAnimation();
Window::SectionSlideParams prepareDialogsAnimation();
void startWithSelf(const MTPVector<MTPUser> &users);
void startWithSelf(const MTPUserFull &user);
void saveSectionInStack();

View File

@ -102,6 +102,10 @@ settingsBlockOneLineTextPart: FlatLabel(settingsPrimaryLabel) {
margin: margins(5px, 5px, 5px, 5px);
maxHeight: 20px;
}
settingsBioValue: FlatLabel(settingsBlockOneLineTextPart) {
width: 120px;
maxHeight: 0px;
}
settingsSubSkip: 4px;
settingsSmallSkip: 10px;
settingsSkip: 14px;

View File

@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "ui/widgets/labels.h"
#include "ui/effects/widget_slide_wrap.h"
#include "boxes/username_box.h"
#include "boxes/add_contact_box.h"
#include "boxes/change_phone_box.h"
#include "observer_peer.h"
#include "messenger.h"
@ -34,7 +35,7 @@ namespace Settings {
using UpdateFlag = Notify::PeerUpdate::Flag;
InfoWidget::InfoWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_info)) {
auto observeEvents = UpdateFlag::UsernameChanged | UpdateFlag::UserPhoneChanged;
auto observeEvents = UpdateFlag::UsernameChanged | UpdateFlag::UserPhoneChanged | UpdateFlag::AboutChanged;
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdated(update);
}));
@ -45,12 +46,13 @@ InfoWidget::InfoWidget(QWidget *parent, UserData *self) : BlockWidget(parent, se
void InfoWidget::createControls() {
style::margins margin(0, -st::settingsBlockOneLineTextPart.margin.top(), 0, st::settingsSmallSkip - st::settingsBlockOneLineTextPart.margin.bottom());
style::margins slidedPadding(0, st::settingsSmallSkip / 2, 0, st::settingsSmallSkip - (st::settingsSmallSkip / 2));
addChildRow(_mobileNumber, margin, slidedPadding);
addChildRow(_username, margin, slidedPadding);
addChildRow(_link, margin, slidedPadding);
addChildRow(_mobileNumber, margin, slidedPadding, st::settingsBlockOneLineTextPart);
addChildRow(_username, margin, slidedPadding, st::settingsBlockOneLineTextPart);
addChildRow(_link, margin, slidedPadding, st::settingsBlockOneLineTextPart);
if (self()->username.isEmpty()) {
_link->hideFast();
}
addChildRow(_bio, margin, slidedPadding, st::settingsBioValue);
refreshControls();
}
@ -58,6 +60,7 @@ void InfoWidget::refreshControls() {
refreshMobileNumber();
refreshUsername();
refreshLink();
refreshBio();
}
void InfoWidget::refreshMobileNumber() {
@ -122,6 +125,24 @@ void InfoWidget::refreshLink() {
}
}
void InfoWidget::refreshBio() {
TextWithEntities bioText;
auto aboutText = self()->about();
if (self()->about().isEmpty()) {
bioText.text = lang(lng_settings_empty_bio);
} else {
bioText.text = aboutText;
}
bioText.entities.push_back(EntityInText(EntityInTextCustomUrl, 0, bioText.text.size(), QString()));
setLabeledText(_bio, lang(lng_profile_bio), bioText, TextWithEntities(), QString());
if (auto text = _bio->entity()->textLabel()) {
text->setClickHandlerHook([](const ClickHandlerPtr &handler, Qt::MouseButton button) {
Ui::show(Box<EditBioBox>(App::self()));
return false;
});
}
}
void InfoWidget::setLabeledText(object_ptr<LabeledWrap> &row, const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString &copyText) {
auto nonEmptyText = !textWithEntities.text.isEmpty();
if (nonEmptyText) {
@ -130,7 +151,8 @@ void InfoWidget::setLabeledText(object_ptr<LabeledWrap> &row, const QString &lab
row->toggleAnimated(nonEmptyText);
}
InfoWidget::LabeledWidget::LabeledWidget(QWidget *parent) : TWidget(parent) {
InfoWidget::LabeledWidget::LabeledWidget(QWidget *parent, const style::FlatLabel &valueSt) : TWidget(parent)
, _valueSt(valueSt) {
}
void InfoWidget::LabeledWidget::setLabeledText(const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString &copyText) {
@ -158,7 +180,7 @@ void InfoWidget::LabeledWidget::setLabelText(object_ptr<Ui::FlatLabel> &text, co
text.destroy();
if (textWithEntities.text.isEmpty()) return;
text.create(this, QString(), Ui::FlatLabel::InitType::Simple, st::settingsBlockOneLineTextPart);
text.create(this, QString(), Ui::FlatLabel::InitType::Simple, _valueSt);
text->show();
text->setMarkedText(textWithEntities);
text->setContextCopyText(copyText);
@ -178,6 +200,9 @@ void InfoWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) {
if (update.flags & (UpdateFlag::UserPhoneChanged)) {
refreshMobileNumber();
}
if (update.flags & UpdateFlag::AboutChanged) {
refreshBio();
}
contentSizeUpdated();
}
@ -221,7 +246,7 @@ int InfoWidget::LabeledWidget::resizeGetHeight(int newWidth) {
_text->show();
}
}
return st::settingsBlockOneLineTextPart.margin.top() + _label->height() + st::settingsBlockOneLineTextPart.margin.bottom();
return st::settingsBlockOneLineTextPart.margin.top() + qMax(_label->height(), _text->height() - st::settingsBlockOneLineTextPart.margin.top() - st::settingsBlockOneLineTextPart.margin.bottom()) + st::settingsBlockOneLineTextPart.margin.bottom();
}
} // namespace Settings

View File

@ -45,10 +45,11 @@ private:
void refreshMobileNumber();
void refreshUsername();
void refreshLink();
void refreshBio();
class LabeledWidget : public TWidget {
public:
LabeledWidget(QWidget *parent);
LabeledWidget(QWidget *parent, const style::FlatLabel &valueSt);
void setLabeledText(const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString &copyText);
@ -63,6 +64,7 @@ private:
private:
void setLabelText(object_ptr<Ui::FlatLabel> &text, const TextWithEntities &textWithEntities, const QString &copyText);
const style::FlatLabel &_valueSt;
object_ptr<Ui::FlatLabel> _label = { nullptr };
object_ptr<Ui::FlatLabel> _text = { nullptr };
object_ptr<Ui::FlatLabel> _shortText = { nullptr };
@ -75,6 +77,7 @@ private:
object_ptr<LabeledWrap> _mobileNumber = { nullptr };
object_ptr<LabeledWrap> _username = { nullptr };
object_ptr<LabeledWrap> _link = { nullptr };
object_ptr<LabeledWrap> _bio = { nullptr };
};