diff --git a/Telegram/Resources/lang.strings b/Telegram/Resources/lang.strings index 30f567731a..e89b8be690 100644 --- a/Telegram/Resources/lang.strings +++ b/Telegram/Resources/lang.strings @@ -124,6 +124,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_flood_error" = "Too many tries. Please try again later."; "lng_gif_error" = "An error has occured while reading GIF animation :("; "lng_edit_error" = "You cannot edit this message"; +"lng_edit_deleted" = "This message was deleted"; +"lng_edit_too_long" = "Your message text is too long"; +"lng_edit_message" = "Edit message"; "lng_deleted" = "Unknown"; "lng_deleted_message" = "Deleted message"; diff --git a/Telegram/SourceFiles/boxes/abstractbox.cpp b/Telegram/SourceFiles/boxes/abstractbox.cpp index ca02a614a7..e9d1783ad5 100644 --- a/Telegram/SourceFiles/boxes/abstractbox.cpp +++ b/Telegram/SourceFiles/boxes/abstractbox.cpp @@ -178,6 +178,14 @@ void AbstractBox::resizeMaxHeight(int32 newWidth, int32 maxHeight) { _maxHeight = maxHeight; resize(newWidth, countHeight()); if (parentWidget()) { + QRect r = geometry(); + int32 parenth = parentWidget()->height(); + if (r.top() + r.height() + st::boxVerticalMargin > parenth) { + int32 newTop = qMax(parenth - int(st::boxVerticalMargin) - r.height(), (parenth - r.height()) / 2); + if (newTop != r.top()) { + move(r.left(), newTop); + } + } parentWidget()->update(geometry().united(g).marginsAdded(QMargins(st::boxShadow.pxWidth(), st::boxShadow.pxHeight(), st::boxShadow.pxWidth(), st::boxShadow.pxHeight()))); } } diff --git a/Telegram/SourceFiles/boxes/photosendbox.cpp b/Telegram/SourceFiles/boxes/photosendbox.cpp index 4bc63c021d..a64a17f357 100644 --- a/Telegram/SourceFiles/boxes/photosendbox.cpp +++ b/Telegram/SourceFiles/boxes/photosendbox.cpp @@ -360,12 +360,12 @@ void PhotoSendBox::onSend(bool ctrlShiftEnter) { onClose(); } -EditPostBox::EditPostBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth) -, _msg(msg) +EditCaptionBox::EditCaptionBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth) +, _msgId(msg->fullId()) , _animated(false) , _photo(false) , _doc(false) -, _text(0) +, _field(0) , _save(this, lang(lng_settings_save), st::defaultBoxButton) , _cancel(this, lang(lng_cancel), st::cancelBoxButton) , _thumbx(0) @@ -383,7 +383,7 @@ EditPostBox::EditPostBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth) ImagePtr image; QString caption; DocumentData *doc = 0; - if (HistoryMedia *media = _msg->getMedia()) { + if (HistoryMedia *media = msg->getMedia()) { HistoryMediaType t = media->type(); switch (t) { case MediaTypeGif: { @@ -489,45 +489,51 @@ EditPostBox::EditPostBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth) } if (_animated || _photo || _doc) { - _text = new InputArea(this, st::confirmCaptionArea, lang(lng_photo_caption), caption); - _text->setMaxLength(MaxPhotoCaption); - _text->setCtrlEnterSubmit(CtrlEnterSubmitBoth); + _field = new InputArea(this, st::confirmCaptionArea, lang(lng_photo_caption), caption); + _field->setMaxLength(MaxPhotoCaption); + _field->setCtrlEnterSubmit(CtrlEnterSubmitBoth); } else { - _text = new InputArea(this, st::editTextArea, lang(lng_edit_placeholder), msg->originalText()); - _text->setMaxLength(MaxMessageSize); - _text->setCtrlEnterSubmit(cCtrlEnter() ? CtrlEnterSubmitCtrlEnter : CtrlEnterSubmitEnter); + QString text = textApplyEntities(msg->originalText(), msg->originalEntities()); + _field = new InputArea(this, st::editTextArea, lang(lng_edit_placeholder), text); +// _field->setMaxLength(MaxMessageSize); // entities can make text in input field larger but still valid + _field->setCtrlEnterSubmit(cCtrlEnter() ? CtrlEnterSubmitCtrlEnter : CtrlEnterSubmitEnter); } updateBoxSize(); - connect(_text, SIGNAL(resized()), this, SLOT(onCaptionResized())); - connect(_text, SIGNAL(submitted(bool)), this, SLOT(onSave(bool))); - connect(_text, SIGNAL(cancelled()), this, SLOT(onClose())); + connect(_field, SIGNAL(submitted(bool)), this, SLOT(onSave(bool))); + connect(_field, SIGNAL(cancelled()), this, SLOT(onClose())); + connect(_field, SIGNAL(resized()), this, SLOT(onCaptionResized())); - QTextCursor c(_text->textCursor()); + QTextCursor c(_field->textCursor()); c.movePosition(QTextCursor::End); - _text->setTextCursor(c); + _field->setTextCursor(c); prepare(); } -void EditPostBox::onCaptionResized() { +bool EditCaptionBox::captionFound() const { + return _animated || _photo || _doc; +} + +void EditCaptionBox::onCaptionResized() { updateBoxSize(); resizeEvent(0); update(); } -void EditPostBox::updateBoxSize() { +void EditCaptionBox::updateBoxSize() { + int32 bottomh = st::boxPhotoCompressedPadding.bottom() + _field->height() + st::normalFont->height + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom(); if (_photo || _animated) { - setMaxHeight(st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom() + st::boxPhotoCompressedPadding.bottom() + _text->height() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom()); + setMaxHeight(st::boxPhotoPadding.top() + _thumbh + bottomh); } else if (_thumbw) { - setMaxHeight(st::boxPhotoPadding.top() + st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom() + st::boxPhotoPadding.bottom() + st::boxPhotoCompressedPadding.bottom() + _text->height() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom()); + setMaxHeight(st::boxPhotoPadding.top() + 0 + st::msgFileThumbSize + 0 + bottomh); } else if (_doc) { - setMaxHeight(st::boxPhotoPadding.top() + st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom() + st::boxPhotoPadding.bottom() + st::boxPhotoCompressedPadding.bottom() + _text->height() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom()); + setMaxHeight(st::boxPhotoPadding.top() + 0 + st::msgFileSize + 0 + bottomh); } else { - setMaxHeight(st::boxPhotoPadding.top() + _text->height() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom()); + setMaxHeight(st::boxPhotoPadding.top() + st::boxTitleFont->height + bottomh); } } -void EditPostBox::paintEvent(QPaintEvent *e) { +void EditCaptionBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; @@ -552,93 +558,108 @@ void EditPostBox::paintEvent(QPaintEvent *e) { } } else if (_doc) { int32 w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); - int32 h = _thumbw ? (st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom()) : (st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom()); - int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0; + int32 h = _thumbw ? (0 + st::msgFileThumbSize + 0) : (0 + st::msgFileSize + 0); + int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0; if (_thumbw) { - nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right(); - nametop = st::msgFileThumbNameTop; - nameright = st::msgFileThumbPadding.left(); - statustop = st::msgFileThumbStatusTop; - linktop = st::msgFileThumbLinkTop; + nameleft = 0 + st::msgFileThumbSize + st::msgFileThumbPadding.right(); + nametop = st::msgFileThumbNameTop - st::msgFileThumbPadding.top(); + nameright = 0; + statustop = st::msgFileThumbStatusTop - st::msgFileThumbPadding.top(); } else { - nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); - nametop = st::msgFileNameTop; - nameright = st::msgFilePadding.left(); - statustop = st::msgFileStatusTop; + nameleft = 0 + st::msgFileSize + st::msgFilePadding.right(); + nametop = st::msgFileNameTop - st::msgFilePadding.top(); + nameright = 0; + statustop = st::msgFileStatusTop - st::msgFilePadding.top(); } - int32 namewidth = w - nameleft - (_thumbw ? st::msgFileThumbPadding.left() : st::msgFilePadding.left()); + int32 namewidth = w - nameleft - 0; if (namewidth > _statusw) { - w -= (namewidth - _statusw); - namewidth = _statusw; + //w -= (namewidth - _statusw); + //namewidth = _statusw; } int32 x = (width() - w) / 2, y = st::boxPhotoPadding.top(); - App::roundRect(p, x, y, w, h, st::msgOutBg, MessageOutCorners, &st::msgOutShadow); +// App::roundRect(p, x, y, w, h, st::msgInBg, MessageInCorners, &st::msgInShadow); if (_thumbw) { - QRect rthumb(rtlrect(x + st::msgFileThumbPadding.left(), y + st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, width())); + QRect rthumb(rtlrect(x + 0, y + 0, st::msgFileThumbSize, st::msgFileThumbSize, width())); p.drawPixmap(rthumb.topLeft(), _thumb); } else { - QRect inner(rtlrect(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, width())); + QRect inner(rtlrect(x + 0, y + 0, st::msgFileSize, st::msgFileSize, width())); p.setPen(Qt::NoPen); - p.setBrush(st::msgFileOutBg); + p.setBrush(st::msgFileInBg); p.setRenderHint(QPainter::HighQualityAntialiasing); p.drawEllipse(inner); p.setRenderHint(QPainter::HighQualityAntialiasing, false); - p.drawSpriteCenter(inner, _isImage ? st::msgFileOutImage : st::msgFileOutFile); + p.drawSpriteCenter(inner, _isImage ? st::msgFileInImage : st::msgFileInFile); } p.setFont(st::semiboldFont); p.setPen(st::black); _name.drawLeftElided(p, x + nameleft, y + nametop, namewidth, width()); - style::color status(st::mediaOutFg); + style::color status(st::mediaInFg); p.setFont(st::normalFont); p.setPen(status); p.drawTextLeft(x + nameleft, y + statustop, width(), _status); + } else { + p.setFont(st::boxTitleFont); + p.setPen(st::black); + p.drawTextLeft(_field->x(), st::boxPhotoPadding.top(), width(), lang(lng_edit_message)); + } + + if (!_error.isEmpty()) { + p.setFont(st::normalFont); + p.setPen(st::setErrColor); + p.drawTextLeft(_field->x(), _field->y() + _field->height() + (st::boxButtonPadding.top() / 2), width(), _error); } } -void EditPostBox::resizeEvent(QResizeEvent *e) { +void EditCaptionBox::resizeEvent(QResizeEvent *e) { _save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height()); _cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y()); - _text->resize(st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), _text->height()); - _text->moveToLeft(st::boxPhotoPadding.left(), _save.y() - st::boxButtonPadding.top() - _text->height()); + _field->resize(st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), _field->height()); + _field->moveToLeft(st::boxPhotoPadding.left(), _save.y() - st::boxButtonPadding.top() - st::normalFont->height - _field->height()); } -void EditPostBox::hideAll() { +void EditCaptionBox::hideAll() { _save.hide(); _cancel.hide(); - _text->hide(); + _field->hide(); } -void EditPostBox::showAll() { +void EditCaptionBox::showAll() { _save.show(); _cancel.show(); - _text->show(); + _field->show(); } -void EditPostBox::showDone() { +void EditCaptionBox::showDone() { setInnerFocus(); } -void EditPostBox::onSave(bool ctrlShiftEnter) { +void EditCaptionBox::onSave(bool ctrlShiftEnter) { if (_saveRequestId) return; + HistoryItem *item = App::histItemById(_msgId); + if (!item) { + _error = lang(lng_edit_deleted); + update(); + return; + } + int32 flags = 0; if (_previewCancelled) { flags |= MTPchannels_EditMessage::flag_no_webpage; } - EntitiesInText sendingEntities; - MTPVector sentEntities = linksToMTP(sendingEntities, true); + MTPVector sentEntities; if (!sentEntities.c_vector().v.isEmpty()) { flags |= MTPmessages_SendMessage::flag_entities; } - _saveRequestId = MTP::send(MTPchannels_EditMessage(MTP_int(flags), _msg->history()->peer->asChannel()->inputChannel, MTP_int(_msg->id), MTP_string(_text->getLastText()), sentEntities), rpcDone(&EditPostBox::saveDone), rpcFail(&EditPostBox::saveFail)); + _saveRequestId = MTP::send(MTPchannels_EditMessage(MTP_int(flags), item->history()->peer->asChannel()->inputChannel, MTP_int(item->id), MTP_string(_field->getLastText()), sentEntities), rpcDone(&EditCaptionBox::saveDone), rpcFail(&EditCaptionBox::saveFail)); } -void EditPostBox::saveDone(const MTPUpdates &updates) { +void EditCaptionBox::saveDone(const MTPUpdates &updates) { _saveRequestId = 0; onClose(); if (App::main()) { @@ -646,7 +667,7 @@ void EditPostBox::saveDone(const MTPUpdates &updates) { } } -bool EditPostBox::saveFail(const RPCError &error) { +bool EditCaptionBox::saveFail(const RPCError &error) { if (mtpIsFlood(error)) return false; _saveRequestId = 0; @@ -657,8 +678,8 @@ bool EditPostBox::saveFail(const RPCError &error) { onClose(); return true; } else if (err == qstr("MESSAGE_EMPTY")) { - _text->setFocus(); - _text->showError(); + _field->setFocus(); + _field->showError(); } else { _error = lang(lng_edit_error); } diff --git a/Telegram/SourceFiles/boxes/photosendbox.h b/Telegram/SourceFiles/boxes/photosendbox.h index 462e8bc503..cc5801b7a7 100644 --- a/Telegram/SourceFiles/boxes/photosendbox.h +++ b/Telegram/SourceFiles/boxes/photosendbox.h @@ -83,17 +83,19 @@ private: }; -class EditPostBox : public AbstractBox, public RPCSender { +class EditCaptionBox : public AbstractBox, public RPCSender { Q_OBJECT public: - EditPostBox(HistoryItem *msg); + EditCaptionBox(HistoryItem *msg); void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); + bool captionFound() const; + void setInnerFocus() { - _text->setFocus(); + _field->setFocus(); } public slots: @@ -114,12 +116,12 @@ private: void saveDone(const MTPUpdates &updates); bool saveFail(const RPCError &error); - HistoryItem *_msg; + FullMsgId _msgId; bool _animated, _photo, _doc; QPixmap _thumb; - InputArea *_text; + InputArea *_field; BoxButton _save, _cancel; int32 _thumbx, _thumby, _thumbw, _thumbh; diff --git a/Telegram/SourceFiles/gui/text.cpp b/Telegram/SourceFiles/gui/text.cpp index 3939945add..b65e30f2c8 100644 --- a/Telegram/SourceFiles/gui/text.cpp +++ b/Telegram/SourceFiles/gui/text.cpp @@ -5049,6 +5049,58 @@ EntitiesInText textParseEntities(QString &text, int32 flags, bool rich) { // som return result; } +QString textApplyEntities(const QString &text, const EntitiesInText &entities) { + if (entities.isEmpty()) return text; + + QMultiMap closingTags; + QString code(qsl("`")), pre(qsl("```")); + + QString result; + int32 size = text.size(); + const QChar *b = text.constData(), *already = b, *e = b + size; + EntitiesInText::const_iterator entity = entities.cbegin(), end = entities.cend(); + while (entity != end && ((entity->type != EntityInTextCode && entity->type != EntityInTextPre) || entity->length <= 0 || entity->offset >= size)) { + ++entity; + } + while (entity != end || !closingTags.isEmpty()) { + int32 nextOpenEntity = (entity == end) ? (size + 1) : entity->offset; + int32 nextCloseEntity = closingTags.isEmpty() ? (size + 1) : closingTags.cbegin().key(); + if (nextOpenEntity <= nextCloseEntity) { + QString tag = (entity->type == EntityInTextCode) ? code : pre; + if (result.isEmpty()) result.reserve(text.size() + entities.size() * pre.size() * 2); + + const QChar *offset = b + nextOpenEntity; + if (offset > already) { + result.append(already, offset - already); + already = offset; + } + result.append(tag); + closingTags.insert(qMin(entity->offset + entity->length, size), tag); + + ++entity; + while (entity != end && ((entity->type != EntityInTextCode && entity->type != EntityInTextPre) || entity->length <= 0 || entity->offset >= size)) { + ++entity; + } + } else { + const QChar *offset = b + nextCloseEntity; + if (offset > already) { + result.append(already, offset - already); + already = offset; + } + result.append(closingTags.cbegin().value()); + closingTags.erase(closingTags.begin()); + } + } + if (result.isEmpty()) { + return text; + } + const QChar *offset = b + size; + if (offset > already) { + result.append(already, offset - already); + } + return result; +} + void emojiDraw(QPainter &p, EmojiPtr e, int x, int y) { p.drawPixmap(QPoint(x, y), App::emoji(), QRect(e->x * ESize, e->y * ESize, ESize, ESize)); } diff --git a/Telegram/SourceFiles/gui/text.h b/Telegram/SourceFiles/gui/text.h index 731e996217..7e270d81e9 100644 --- a/Telegram/SourceFiles/gui/text.h +++ b/Telegram/SourceFiles/gui/text.h @@ -110,6 +110,7 @@ inline MTPVector linksToMTP(const EntitiesInText &links, bool return result; } EntitiesInText textParseEntities(QString &text, int32 flags, bool rich = false); // changes text if (flags & TextParseMono) +QString textApplyEntities(const QString &text, const EntitiesInText &entities); #include "gui/emoji_config.h" diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index fd713cf661..bba4594afa 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -6637,7 +6637,13 @@ void HistoryWidget::onEditMessage() { HistoryItem *to = App::contextItem(); if (!to || !to->history()->peer->isChannel()) return; - Ui::showLayer(new EditPostBox(to)); + EditCaptionBox *box = new EditCaptionBox(to); + if (box->captionFound()) { + Ui::showLayer(box); + } else { + delete box; + // edit post + } } bool HistoryWidget::lastForceReplyReplied(const FullMsgId &replyTo) const {