beta 9026001 message/post edit done

This commit is contained in:
John Preston 2016-02-25 13:32:31 +03:00
parent 9c8ae7f32b
commit 4ec579112c
18 changed files with 660 additions and 259 deletions

View File

@ -127,6 +127,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_edit_deleted" = "This message was deleted"; "lng_edit_deleted" = "This message was deleted";
"lng_edit_too_long" = "Your message text is too long"; "lng_edit_too_long" = "Your message text is too long";
"lng_edit_message" = "Edit message"; "lng_edit_message" = "Edit message";
"lng_edit_message_text" = "New message text..";
"lng_deleted" = "Unknown"; "lng_deleted" = "Unknown";
"lng_deleted_message" = "Deleted message"; "lng_deleted_message" = "Deleted message";
@ -653,6 +654,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_comment_ph" = "Write a comment.."; "lng_comment_ph" = "Write a comment..";
"lng_broadcast_ph" = "Broadcast a message.."; "lng_broadcast_ph" = "Broadcast a message..";
"lng_record_cancel" = "Release outside this field to cancel"; "lng_record_cancel" = "Release outside this field to cancel";
"lng_will_be_notified" = "Members will be notified when you post";
"lng_wont_be_notified" = "Members will not be notified when you post";
"lng_empty_history" = ""; "lng_empty_history" = "";
"lng_willbe_history" = "Please select a chat to start messaging"; "lng_willbe_history" = "Please select a chat to start messaging";
"lng_message_with_from" = "[c]{from}:[/c] {message}"; "lng_message_with_from" = "[c]{from}:[/c] {message}";
@ -712,6 +715,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_context_open_link" = "Open Link"; "lng_context_open_link" = "Open Link";
"lng_context_copy_link" = "Copy Link"; "lng_context_copy_link" = "Copy Link";
"lng_context_copy_post_link" = "Copy Post Link";
"lng_context_open_email" = "Write to this address"; "lng_context_open_email" = "Write to this address";
"lng_context_copy_email" = "Copy email address"; "lng_context_copy_email" = "Copy email address";
"lng_context_open_hashtag" = "Search by hashtag"; "lng_context_open_hashtag" = "Search by hashtag";

View File

@ -1429,6 +1429,7 @@ replyTop: 8px;
replyBottom: 6px; replyBottom: 6px;
replyIconPos: point(13px, 13px); replyIconPos: point(13px, 13px);
replyIcon: sprite(343px, 197px, 24px, 24px); replyIcon: sprite(343px, 197px, 24px, 24px);
editIcon: sprite(371px, 286px, 24px, 24px);
replyCancel: iconedButton(btnDefIconed) { replyCancel: iconedButton(btnDefIconed) {
icon: sprite(165px, 24px, 14px, 14px); icon: sprite(165px, 24px, 14px, 14px);
iconPos: point(17px, 17px); iconPos: point(17px, 17px);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 KiB

After

Width:  |  Height:  |  Size: 239 KiB

View File

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
static const int32 AppVersion = 9026; static const int32 AppVersion = 9026;
static const wchar_t *AppVersionStr = L"0.9.26"; static const wchar_t *AppVersionStr = L"0.9.26";
static const bool DevVersion = false; static const bool DevVersion = false;
//#define BETA_VERSION (9019002ULL) // just comment this line to build public version #define BETA_VERSION (9026001ULL) // just comment this line to build public version
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)"; static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
static const wchar_t *AppName = L"Telegram Desktop"; static const wchar_t *AppName = L"Telegram Desktop";

View File

@ -280,7 +280,8 @@ History::History(const PeerId &peerId) : width(0), height(0)
, oldLoaded(false) , oldLoaded(false)
, newLoaded(true) , newLoaded(true)
, lastMsg(0) , lastMsg(0)
, draftToId(0) , msgDraft(0)
, editDraft(0)
, lastWidth(0) , lastWidth(0)
, lastScrollTop(ScrollMax) , lastScrollTop(ScrollMax)
, lastShowAtMsgId(ShowAtUnreadMsgId) , lastShowAtMsgId(ShowAtUnreadMsgId)
@ -294,8 +295,7 @@ History::History(const PeerId &peerId) : width(0), height(0)
, textCachedFor(0) , textCachedFor(0)
, lastItemTextCache(st::dlgRichMinWidth) , lastItemTextCache(st::dlgRichMinWidth)
, posInDialogs(0) , posInDialogs(0)
, typingText(st::dlgRichMinWidth) , typingText(st::dlgRichMinWidth) {
{
if (peer->isChannel() || (peer->isUser() && peer->asUser()->botInfo)) { if (peer->isChannel() || (peer->isUser() && peer->asUser()->botInfo)) {
outboxReadBefore = INT_MAX; outboxReadBefore = INT_MAX;
} }
@ -2674,6 +2674,12 @@ void History::removeBlock(HistoryBlock *block) {
delete block; delete block;
} }
History::~History() {
clear();
deleteAndMark(msgDraft);
deleteAndMark(editDraft);
}
int32 HistoryBlock::geomResize(int32 newWidth, int32 *ytransform, const HistoryItem *resizedItem) { int32 HistoryBlock::geomResize(int32 newWidth, int32 *ytransform, const HistoryItem *resizedItem) {
int32 y = 0; int32 y = 0;
for (Items::iterator i = items.begin(), e = items.end(); i != e; ++i) { for (Items::iterator i = items.begin(), e = items.end(); i != e; ++i) {
@ -2926,7 +2932,8 @@ bool HistoryItem::canEdit(const QDateTime &cur) const {
t != MediaTypeFile && t != MediaTypeFile &&
t != MediaTypeGif && t != MediaTypeGif &&
t != MediaTypeMusicFile && t != MediaTypeMusicFile &&
t != MediaTypeVoiceFile) { t != MediaTypeVoiceFile &&
t != MediaTypeWebPage) {
return false; return false;
} }
} }

View File

@ -149,6 +149,42 @@ struct SendAction {
int32 progress; int32 progress;
}; };
struct HistoryDraft {
HistoryDraft() : msgId(0), previewCancelled(false) {
}
HistoryDraft(const QString &text, MsgId msgId, const MessageCursor &cursor, bool previewCancelled)
: text(text)
, msgId(msgId)
, cursor(cursor)
, previewCancelled(previewCancelled) {
}
HistoryDraft(const FlatTextarea &field, MsgId msgId, bool previewCancelled)
: text(field.getLastText())
, msgId(msgId)
, cursor(field)
, previewCancelled(previewCancelled) {
}
QString text;
MsgId msgId; // replyToId for message draft, editMsgId for edit draft
MessageCursor cursor;
bool previewCancelled;
};
struct HistoryEditDraft : public HistoryDraft {
HistoryEditDraft()
: HistoryDraft()
, saveRequest(0) {
}
HistoryEditDraft(const QString &text, MsgId msgId, const MessageCursor &cursor, bool previewCancelled, mtpRequestId saveRequest = 0)
: HistoryDraft(text, msgId, cursor, previewCancelled)
, saveRequest(saveRequest) {
}
HistoryEditDraft(const FlatTextarea &field, MsgId msgId, bool previewCancelled, mtpRequestId saveRequest = 0)
: HistoryDraft(field, msgId, previewCancelled)
, saveRequest(saveRequest) {
}
mtpRequestId saveRequest;
};
class HistoryMedia; class HistoryMedia;
class HistoryMessage; class HistoryMessage;
class HistoryUnreadBar; class HistoryUnreadBar;
@ -184,9 +220,7 @@ public:
void blockResized(HistoryBlock *block, int32 dh); void blockResized(HistoryBlock *block, int32 dh);
void removeBlock(HistoryBlock *block); void removeBlock(HistoryBlock *block);
virtual ~History() { virtual ~History();
clear();
}
HistoryItem *createItem(HistoryBlock *block, const MTPMessage &msg, bool applyServiceAction); HistoryItem *createItem(HistoryBlock *block, const MTPMessage &msg, bool applyServiceAction);
HistoryItem *createItemForwarded(HistoryBlock *block, MsgId id, int32 flags, QDateTime date, int32 from, HistoryMessage *msg); HistoryItem *createItemForwarded(HistoryBlock *block, MsgId id, int32 flags, QDateTime date, int32 from, HistoryMessage *msg);
@ -284,10 +318,20 @@ public:
typedef QList<HistoryItem*> NotifyQueue; typedef QList<HistoryItem*> NotifyQueue;
NotifyQueue notifies; NotifyQueue notifies;
QString draft; HistoryDraft *msgDraft;
MsgId draftToId; HistoryEditDraft *editDraft;
MessageCursor draftCursor; HistoryDraft *draft() {
bool draftPreviewCancelled; return editDraft ? editDraft : msgDraft;
}
void setMsgDraft(HistoryDraft *draft) {
if (msgDraft) delete msgDraft;
msgDraft = draft;
}
void setEditDraft(HistoryEditDraft *draft) {
if (editDraft) delete editDraft;
editDraft = draft;
}
int32 lastWidth, lastScrollTop; int32 lastWidth, lastScrollTop;
MsgId lastShowAtMsgId; MsgId lastShowAtMsgId;
bool mute; bool mute;

View File

@ -2609,9 +2609,11 @@ void CollapseButton::paintEvent(QPaintEvent *e) {
HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
, _replyToId(0) , _replyToId(0)
, _replyTo(0)
, _replyToNameVersion(0) , _replyToNameVersion(0)
, _replyForwardPreviewCancel(this, st::replyCancel) , _editMsgId(0)
, _replyEditMsg(0)
, _fieldBarCancel(this, st::replyCancel)
, _saveEditMsgRequestId(0)
, _reportSpamStatus(dbiprsUnknown) , _reportSpamStatus(dbiprsUnknown)
, _previewData(0) , _previewData(0)
, _previewRequest(0) , _previewRequest(0)
@ -2661,7 +2663,10 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
, _field(this, st::taMsgField, lang(lng_message_ph)) , _field(this, st::taMsgField, lang(lng_message_ph))
, _a_record(animation(this, &HistoryWidget::step_record)) , _a_record(animation(this, &HistoryWidget::step_record))
, _a_recording(animation(this, &HistoryWidget::step_recording)) , _a_recording(animation(this, &HistoryWidget::step_recording))
, _recording(false), _inRecord(false), _inField(false), _inReply(false) , _recording(false)
, _inRecord(false)
, _inField(false)
, _inReplyEdit(false)
, a_recordingLevel(0, 0), _recordingSamples(0) , a_recordingLevel(0, 0), _recordingSamples(0)
, a_recordOver(0, 0), a_recordDown(0, 0), a_recordCancel(st::recordCancel->c, st::recordCancel->c) , a_recordOver(0, 0), a_recordDown(0, 0), a_recordCancel(st::recordCancel->c, st::recordCancel->c)
, _recordCancelWidth(st::recordFont->width(lang(lng_record_cancel))) , _recordCancelWidth(st::recordFont->width(lang(lng_record_cancel)))
@ -2697,7 +2702,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
connect(&_reportSpamPanel, SIGNAL(clearClicked()), this, SLOT(onReportSpamClear())); connect(&_reportSpamPanel, SIGNAL(clearClicked()), this, SLOT(onReportSpamClear()));
connect(&_toHistoryEnd, SIGNAL(clicked()), this, SLOT(onHistoryToEnd())); connect(&_toHistoryEnd, SIGNAL(clicked()), this, SLOT(onHistoryToEnd()));
connect(&_collapseComments, SIGNAL(clicked()), this, SLOT(onCollapseComments())); connect(&_collapseComments, SIGNAL(clicked()), this, SLOT(onCollapseComments()));
connect(&_replyForwardPreviewCancel, SIGNAL(clicked()), this, SLOT(onReplyForwardPreviewCancel())); connect(&_fieldBarCancel, SIGNAL(clicked()), this, SLOT(onFieldBarCancel()));
connect(&_send, SIGNAL(clicked()), this, SLOT(onSend())); connect(&_send, SIGNAL(clicked()), this, SLOT(onSend()));
connect(&_unblock, SIGNAL(clicked()), this, SLOT(onUnblock())); connect(&_unblock, SIGNAL(clicked()), this, SLOT(onUnblock()));
connect(&_botStart, SIGNAL(clicked()), this, SLOT(onBotStart())); connect(&_botStart, SIGNAL(clicked()), this, SLOT(onBotStart()));
@ -2745,7 +2750,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
connect(&_field, SIGNAL(cursorPositionChanged()), this, SLOT(onDraftSaveDelayed())); connect(&_field, SIGNAL(cursorPositionChanged()), this, SLOT(onDraftSaveDelayed()));
connect(&_field, SIGNAL(cursorPositionChanged()), this, SLOT(onCheckMentionDropdown()), Qt::QueuedConnection); connect(&_field, SIGNAL(cursorPositionChanged()), this, SLOT(onCheckMentionDropdown()), Qt::QueuedConnection);
_replyForwardPreviewCancel.hide(); _fieldBarCancel.hide();
_scroll.hide(); _scroll.hide();
_scroll.move(0, 0); _scroll.move(0, 0);
@ -2897,20 +2902,20 @@ void HistoryWidget::onTextChange() {
updateStickersByEmoji(); updateStickersByEmoji();
if (_peer && (!_peer->isChannel() || _peer->isMegagroup() || !_peer->asChannel()->canPublish() || (!_peer->asChannel()->isBroadcast() && !_broadcast.checked()))) { if (_peer && (!_peer->isChannel() || _peer->isMegagroup() || !_peer->asChannel()->canPublish() || (!_peer->asChannel()->isBroadcast() && !_broadcast.checked()))) {
if (!_inlineBot && (_textUpdateEventsFlags & TextUpdateEventsSendTyping)) { if (!_inlineBot && !_editMsgId && (_textUpdateEventsFlags & TextUpdateEventsSendTyping)) {
updateSendAction(_history, SendActionTyping); updateSendAction(_history, SendActionTyping);
} }
} }
if (cHasAudioCapture()) { if (cHasAudioCapture()) {
if (!_field.hasSendText() && !readyToForward()) { if (!_field.hasSendText() && !readyToForward() && !_editMsgId) {
_previewCancelled = false; _previewCancelled = false;
_send.hide(); _send.hide();
setMouseTracking(true); updateMouseTracking();
mouseMoveEvent(0); mouseMoveEvent(0);
} else if (!_field.isHidden() && _send.isHidden()) { } else if (!_field.isHidden() && _send.isHidden()) {
_send.show(); _send.show();
setMouseTracking(false); updateMouseTracking();
_a_record.stop(); _a_record.stop();
_inRecord = _inField = false; _inRecord = _inField = false;
a_recordOver = a_recordDown = anim::fvalue(0, 0); a_recordOver = a_recordDown = anim::fvalue(0, 0);
@ -2931,7 +2936,9 @@ void HistoryWidget::onTextChange() {
void HistoryWidget::onDraftSaveDelayed() { void HistoryWidget::onDraftSaveDelayed() {
if (!_peer || !(_textUpdateEventsFlags & TextUpdateEventsSaveDraft)) return; if (!_peer || !(_textUpdateEventsFlags & TextUpdateEventsSaveDraft)) return;
if (!_field.textCursor().anchor() && !_field.textCursor().position() && !_field.verticalScrollBar()->value()) { if (!_field.textCursor().anchor() && !_field.textCursor().position() && !_field.verticalScrollBar()->value()) {
if (!Local::hasDraftPositions(_peer->id)) return; if (!Local::hasDraftCursors(_peer->id)) {
return;
}
} }
onDraftSave(true); onDraftSave(true);
} }
@ -2947,30 +2954,77 @@ void HistoryWidget::onDraftSave(bool delayed) {
return _saveDraftTimer.start(SaveDraftTimeout); return _saveDraftTimer.start(SaveDraftTimeout);
} }
} }
writeDraft(); writeDrafts(Nil, Nil);
} }
void HistoryWidget::writeDraft(MsgId *replyTo, const QString *text, const MessageCursor *cursor, bool *previewCancelled) { void HistoryWidget::writeDrafts(HistoryDraft **msgDraft, HistoryEditDraft **editDraft) {
if (!msgDraft && _editMsgId) msgDraft = &_history->msgDraft;
bool save = _peer && (_saveDraftStart > 0); bool save = _peer && (_saveDraftStart > 0);
_saveDraftStart = 0; _saveDraftStart = 0;
_saveDraftTimer.stop(); _saveDraftTimer.stop();
if (_saveDraftText) { if (_saveDraftText) {
if (save) { if (save) {
Local::writeDraft(_peer->id, Local::MessageDraft(replyTo ? (*replyTo) : _replyToId, text ? (*text) : _field.getLastText(), previewCancelled ? (*previewCancelled) : _previewCancelled)); Local::MessageDraft localMsgDraft, localEditDraft;
if (msgDraft) {
if (*msgDraft) {
localMsgDraft = Local::MessageDraft((*msgDraft)->msgId, (*msgDraft)->text, (*msgDraft)->previewCancelled);
}
} else {
localMsgDraft = Local::MessageDraft(_replyToId, _field.getLastText(), _previewCancelled);
}
if (editDraft) {
if (*editDraft) {
localEditDraft = Local::MessageDraft((*editDraft)->msgId, (*editDraft)->text, (*editDraft)->previewCancelled);
}
} else if (_editMsgId) {
localEditDraft = Local::MessageDraft(_editMsgId, _field.getLastText(), _previewCancelled);
}
Local::writeDrafts(_peer->id, localMsgDraft, localEditDraft);
if (_migrated) { if (_migrated) {
Local::writeDraft(_migrated->peer->id, Local::MessageDraft()); Local::writeDrafts(_migrated->peer->id, Local::MessageDraft(), Local::MessageDraft());
} }
} }
_saveDraftText = false; _saveDraftText = false;
} }
if (save) { if (save) {
Local::writeDraftPositions(_peer->id, cursor ? (*cursor) : MessageCursor(_field)); MessageCursor msgCursor, editCursor;
if (msgDraft) {
if (*msgDraft) {
msgCursor = (*msgDraft)->cursor;
}
} else {
msgCursor = MessageCursor(_field);
}
if (editDraft) {
if (*editDraft) {
editCursor = (*editDraft)->cursor;
}
} else if (_editMsgId) {
editCursor = MessageCursor(_field);
}
Local::writeDraftCursors(_peer->id, msgCursor, editCursor);
if (_migrated) { if (_migrated) {
Local::writeDraftPositions(_migrated->peer->id, MessageCursor()); Local::writeDraftCursors(_migrated->peer->id, MessageCursor(), MessageCursor());
} }
} }
} }
void HistoryWidget::writeDrafts(History *history) {
Local::MessageDraft localMsgDraft, localEditDraft;
MessageCursor msgCursor, editCursor;
if (history->msgDraft) {
localMsgDraft = Local::MessageDraft(history->msgDraft->msgId, history->msgDraft->text, history->msgDraft->previewCancelled);
msgCursor = history->msgDraft->cursor;
}
if (history->editDraft) {
localEditDraft = Local::MessageDraft(history->editDraft->msgId, history->editDraft->text, history->editDraft->previewCancelled);
editCursor = history->editDraft->cursor;
}
Local::writeDrafts(history->peer->id, localMsgDraft, localEditDraft);
Local::writeDraftCursors(history->peer->id, msgCursor, editCursor);
}
void HistoryWidget::cancelSendAction(History *history, SendActionType type) { void HistoryWidget::cancelSendAction(History *history, SendActionType type) {
QMap<QPair<History*, SendActionType>, mtpRequestId>::iterator i = _sendActionRequests.find(qMakePair(history, type)); QMap<QPair<History*, SendActionType>, mtpRequestId>::iterator i = _sendActionRequests.find(qMakePair(history, type));
if (i != _sendActionRequests.cend()) { if (i != _sendActionRequests.cend()) {
@ -3374,16 +3428,36 @@ void HistoryWidget::fastShowAtEnd(History *h) {
} }
void HistoryWidget::applyDraft(bool parseLinks) { void HistoryWidget::applyDraft(bool parseLinks) {
if (!_history) return; HistoryDraft *draft = _history ? _history->draft() : 0;
setFieldText(_history->draft); if (!draft) {
_field.setFocus(); setFieldText(QString());
_field.setFocus();
_editMsgId = _replyToId = 0;
return;
}
_textUpdateEventsFlags = 0; _textUpdateEventsFlags = 0;
_history->draftCursor.applyTo(_field); setFieldText(draft->text);
_field.setFocus();
draft->cursor.applyTo(_field);
_textUpdateEventsFlags = TextUpdateEventsSaveDraft | TextUpdateEventsSendTyping; _textUpdateEventsFlags = TextUpdateEventsSaveDraft | TextUpdateEventsSendTyping;
_previewCancelled = _history->draftPreviewCancelled; _previewCancelled = draft->previewCancelled;
if (_history->editDraft) {
_editMsgId = _history->editDraft->msgId;
_replyToId = 0;
} else {
_editMsgId = 0;
_replyToId = readyToForward() ? 0 : _history->msgDraft->msgId;
}
if (parseLinks) { if (parseLinks) {
onPreviewParse(); onPreviewParse();
} }
if (_editMsgId || _replyToId) {
updateReplyEditTexts();
if (!_replyEditMsg && App::api()) {
App::api()->requestReplyTo(0, _peer->asChannel(), _editMsgId ? _editMsgId : _replyToId);
}
}
} }
void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool reload) { void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool reload) {
@ -3441,13 +3515,22 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
clearAllLoadRequests(); clearAllLoadRequests();
if (_history) { if (_history) {
_history->draft = _field.getLastText(); if (_editMsgId) {
if (_migrated) _migrated->draft = QString(); // use migrated draft only once _history->setEditDraft(new HistoryEditDraft(_field, _editMsgId, _previewCancelled, _saveEditMsgRequestId));
_history->draftCursor.fillFrom(_field); } else {
_history->draftToId = _replyToId; if (_replyToId || !_field.getLastText().isEmpty()) {
_history->draftPreviewCancelled = _previewCancelled; _history->setMsgDraft(new HistoryDraft(_field, _replyToId, _previewCancelled));
} else {
_history->setMsgDraft(Nil);
}
_history->setEditDraft(Nil);
}
if (_migrated) {
_migrated->setMsgDraft(Nil); // use migrated draft only once
_migrated->setEditDraft(Nil);
}
writeDraft(&_history->draftToId, &_history->draft, &_history->draftCursor, &_history->draftPreviewCancelled); writeDrafts(&_history->msgDraft, &_history->editDraft);
if (_scroll.scrollTop() + 1 <= _scroll.scrollTopMax()) { if (_scroll.scrollTop() + 1 <= _scroll.scrollTopMax()) {
_history->lastWidth = _list->width(); _history->lastWidth = _list->width();
@ -3467,16 +3550,14 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
updateBotKeyboard(); updateBotKeyboard();
} }
if (_replyToId) { _editMsgId = 0;
_replyTo = 0; _saveEditMsgRequestId = 0;
_replyToId = 0; _replyToId = 0;
_replyForwardPreviewCancel.hide(); _replyEditMsg = 0;
} _previewData = 0;
if (_previewData && _previewData->pendingTill >= 0) {
_previewData = 0;
_replyForwardPreviewCancel.hide();
}
_previewCache.clear(); _previewCache.clear();
_fieldBarCancel.hide();
if (_list) _list->deleteLater(); if (_list) _list->deleteLater();
_list = 0; _list = 0;
_scroll.takeWidget(); _scroll.takeWidget();
@ -3552,39 +3633,20 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
App::main()->peerUpdated(_peer); App::main()->peerUpdated(_peer);
if (_history->draftToId > 0 || !_history->draft.isEmpty()) { Local::readDraftsWithCursors(_history);
applyDraft(false); if (_migrated) {
_replyToId = readyToForward() ? 0 : _history->draftToId; Local::readDraftsWithCursors(_migrated);
} else if (_migrated && !_migrated->draft.isEmpty()) { _migrated->setEditDraft(Nil);
_history->draft = _migrated->draft; if (_migrated->msgDraft && !_migrated->msgDraft->text.isEmpty()) {
_history->draftCursor = _migrated->draftCursor; _migrated->msgDraft->msgId = 0; // edit and reply to drafts can't migrate
_history->draftPreviewCancelled = _migrated->draftPreviewCancelled; if (!_history->msgDraft) {
_history->draftToId = 0; _history->setMsgDraft(new HistoryDraft(*_migrated->msgDraft));
_migrated->draft = QString(); // use migrated draft only once }
applyDraft(false);
_replyToId = 0;
} else {
bool fromMigrated = false;
Local::MessageDraft draft = Local::readDraft(_peer->id);
if (draft.replyTo <= 0 && draft.text.isEmpty() && _migrated) {
fromMigrated = true;
draft = Local::readDraft(_migrated->peer->id);
} }
setFieldText(draft.text); _migrated->setMsgDraft(Nil);
_field.setFocus();
if (!draft.text.isEmpty()) {
MessageCursor cur = Local::readDraftPositions(fromMigrated ? _migrated->peer->id : _peer->id);
_textUpdateEventsFlags = 0;
cur.applyTo(_field);
_textUpdateEventsFlags = TextUpdateEventsSaveDraft | TextUpdateEventsSendTyping;
}
_replyToId = readyToForward() ? 0 : draft.replyTo;
_previewCancelled = draft.previewCancelled;
}
if (_replyToId) {
updateReplyTo();
if (!_replyTo && App::api()) App::api()->requestReplyTo(0, _peer->asChannel(), _replyToId);
} }
applyDraft(false);
resizeEvent(0); resizeEvent(0);
if (!_previewCancelled) { if (!_previewCancelled) {
onPreviewParse(); onPreviewParse();
@ -3755,7 +3817,7 @@ void HistoryWidget::updateControlsVisibility() {
_muteUnmute.hide(); _muteUnmute.hide();
_attachMention.hide(); _attachMention.hide();
_field.hide(); _field.hide();
_replyForwardPreviewCancel.hide(); _fieldBarCancel.hide();
_attachDocument.hide(); _attachDocument.hide();
_attachPhoto.hide(); _attachPhoto.hide();
_attachEmoji.hide(); _attachEmoji.hide();
@ -3812,7 +3874,7 @@ void HistoryWidget::updateControlsVisibility() {
_attachPhoto.hide(); _attachPhoto.hide();
_broadcast.hide(); _broadcast.hide();
_kbScroll.hide(); _kbScroll.hide();
_replyForwardPreviewCancel.hide(); _fieldBarCancel.hide();
_attachDocument.hide(); _attachDocument.hide();
_attachPhoto.hide(); _attachPhoto.hide();
_attachEmoji.hide(); _attachEmoji.hide();
@ -3849,7 +3911,7 @@ void HistoryWidget::updateControlsVisibility() {
_attachPhoto.hide(); _attachPhoto.hide();
_broadcast.hide(); _broadcast.hide();
_kbScroll.hide(); _kbScroll.hide();
_replyForwardPreviewCancel.hide(); _fieldBarCancel.hide();
} else { } else {
_unblock.hide(); _unblock.hide();
_botStart.hide(); _botStart.hide();
@ -3857,11 +3919,9 @@ void HistoryWidget::updateControlsVisibility() {
_muteUnmute.hide(); _muteUnmute.hide();
if (cHasAudioCapture() && !_field.hasSendText() && !readyToForward()) { if (cHasAudioCapture() && !_field.hasSendText() && !readyToForward()) {
_send.hide(); _send.hide();
setMouseTracking(true);
mouseMoveEvent(0); mouseMoveEvent(0);
} else { } else {
_send.show(); _send.show();
setMouseTracking(false);
_a_record.stop(); _a_record.stop();
_inRecord = _inField = false; _inRecord = _inField = false;
a_recordOver = anim::fvalue(0, 0); a_recordOver = anim::fvalue(0, 0);
@ -3924,14 +3984,14 @@ void HistoryWidget::updateControlsVisibility() {
} }
updateFieldPlaceholder(); updateFieldPlaceholder();
} }
if (_replyToId || readyToForward() || (_previewData && _previewData->pendingTill >= 0) || _kbReplyTo) { if (_editMsgId || _replyToId || readyToForward() || (_previewData && _previewData->pendingTill >= 0) || _kbReplyTo) {
if (_replyForwardPreviewCancel.isHidden()) { if (_fieldBarCancel.isHidden()) {
_replyForwardPreviewCancel.show(); _fieldBarCancel.show();
resizeEvent(0); resizeEvent(0);
update(); update();
} }
} else { } else {
_replyForwardPreviewCancel.hide(); _fieldBarCancel.hide();
} }
} }
} else { } else {
@ -3945,7 +4005,7 @@ void HistoryWidget::updateControlsVisibility() {
_attachPhoto.hide(); _attachPhoto.hide();
_broadcast.hide(); _broadcast.hide();
_kbScroll.hide(); _kbScroll.hide();
_replyForwardPreviewCancel.hide(); _fieldBarCancel.hide();
_attachDocument.hide(); _attachDocument.hide();
_attachPhoto.hide(); _attachPhoto.hide();
_attachEmoji.hide(); _attachEmoji.hide();
@ -3961,6 +4021,12 @@ void HistoryWidget::updateControlsVisibility() {
update(); update();
} }
} }
updateMouseTracking();
}
void HistoryWidget::updateMouseTracking() {
bool trackMouse = !_fieldBarCancel.isHidden() || (cHasAudioCapture() && _send.isHidden() && !_field.isHidden());
setMouseTracking(trackMouse);
} }
void HistoryWidget::newUnreadMsg(History *history, HistoryItem *item) { void HistoryWidget::newUnreadMsg(History *history, HistoryItem *item) {
@ -4432,12 +4498,84 @@ void HistoryWidget::onCollapseComments() {
showHistory(_peer->id, switchAt); showHistory(_peer->id, switchAt);
} }
void HistoryWidget::saveEditMsg() {
if (_saveEditMsgRequestId) return;
WebPageId webPageId = _previewCancelled ? CancelledWebPageId : ((_previewData && _previewData->pendingTill >= 0) ? _previewData->id : 0);
EntitiesInText sendingEntities, leftEntities;
QString sendingText, leftText = prepareTextWithEntities(_field.getLastText(), leftEntities, itemTextOptions(_history, App::self()).flags);
if (!textSplit(sendingText, sendingEntities, leftText, leftEntities, MaxMessageSize)) {
_field.selectAll();
_field.setFocus();
return;
} else if (!leftText.isEmpty()) {
Ui::showLayer(new InformBox(lang(lng_edit_too_long)));
return;
}
int32 sendFlags = 0;
if (webPageId == CancelledWebPageId) {
sendFlags |= MTPmessages_SendMessage::flag_no_webpage;
}
MTPVector<MTPMessageEntity> localEntities = linksToMTP(sendingEntities), sentEntities = linksToMTP(sendingEntities, true);
if (!sentEntities.c_vector().v.isEmpty()) {
sendFlags |= MTPmessages_SendMessage::flag_entities;
}
_saveEditMsgRequestId = MTP::send(MTPchannels_EditMessage(MTP_int(sendFlags), _history->peer->asChannel()->inputChannel, MTP_int(_editMsgId), MTP_string(sendingText), sentEntities), rpcDone(&HistoryWidget::saveEditMsgDone, _history), rpcFail(&HistoryWidget::saveEditMsgFail, _history));
}
void HistoryWidget::saveEditMsgDone(History *history, const MTPUpdates &updates, mtpRequestId req) {
if (App::main()) {
App::main()->sentUpdatesReceived(updates);
}
if (req == _saveEditMsgRequestId) {
_saveEditMsgRequestId = 0;
cancelEdit();
}
if (history->editDraft && history->editDraft->saveRequest == req) {
history->setEditDraft(Nil);
writeDrafts(history);
}
}
bool HistoryWidget::saveEditMsgFail(History *history, const RPCError &error, mtpRequestId req) {
if (mtpIsFlood(error)) return false;
if (req == _saveEditMsgRequestId) {
_saveEditMsgRequestId = 0;
}
if (history->editDraft && history->editDraft->saveRequest == req) {
history->editDraft->saveRequest = 0;
}
QString err = error.type();
if (err == qstr("MESSAGE_ID_INVALID") || err == qstr("CHAT_ADMIN_REQUIRED") || err == qstr("MESSAGE_EDIT_TIME_EXPIRED")) {
Ui::showLayer(new InformBox(lang(lng_edit_error)));
} else if (err == qstr("MESSAGE_NOT_MODIFIED")) {
cancelEdit();
} else if (err == qstr("MESSAGE_EMPTY")) {
_field.selectAll();
_field.setFocus();
} else {
Ui::showLayer(new InformBox(lang(lng_edit_error)));
}
update();
return true;
}
void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) { void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) {
if (!_history) return; if (!_history) return;
if (_editMsgId) {
saveEditMsg();
return;
}
bool lastKeyboardUsed = lastForceReplyReplied(FullMsgId(_channel, replyTo)); bool lastKeyboardUsed = lastForceReplyReplied(FullMsgId(_channel, replyTo));
WebPageId webPageId = _previewCancelled ? CancelledWebPageId : ((_previewData && _previewData->pendingTill >= 0) ? _previewData->id : 0); WebPageId webPageId = _previewCancelled ? CancelledWebPageId : ((_previewData && _previewData->pendingTill >= 0) ? _previewData->id : 0);
App::main()->sendMessage(_history, _field.getLastText(), replyTo, _broadcast.checked(), webPageId); App::main()->sendMessage(_history, _field.getLastText(), replyTo, _broadcast.checked(), webPageId);
setFieldText(QString()); setFieldText(QString());
@ -4658,7 +4796,7 @@ void HistoryWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTo
_kbHide.hide(); _kbHide.hide();
_cmdStart.hide(); _cmdStart.hide();
_field.hide(); _field.hide();
_replyForwardPreviewCancel.hide(); _fieldBarCancel.hide();
_send.hide(); _send.hide();
_unblock.hide(); _unblock.hide();
_botStart.hide(); _botStart.hide();
@ -4846,7 +4984,7 @@ void HistoryWidget::mouseMoveEvent(QMouseEvent *e) {
QPoint pos(e ? e->pos() : mapFromGlobal(QCursor::pos())); QPoint pos(e ? e->pos() : mapFromGlobal(QCursor::pos()));
bool inRecord = _send.geometry().contains(pos); bool inRecord = _send.geometry().contains(pos);
bool inField = pos.y() >= (_scroll.y() + _scroll.height()) && pos.y() < height() && pos.x() >= 0 && pos.x() < width(); bool inField = pos.y() >= (_scroll.y() + _scroll.height()) && pos.y() < height() && pos.x() >= 0 && pos.x() < width();
bool inReply = QRect(st::replySkip, _field.y() - st::sendPadding - st::replyHeight, width() - st::replySkip - _replyForwardPreviewCancel.width(), st::replyHeight).contains(pos) && replyToId(); bool inReplyEdit = QRect(st::replySkip, _field.y() - st::sendPadding - st::replyHeight, width() - st::replySkip - _fieldBarCancel.width(), st::replyHeight).contains(pos) && (_editMsgId || replyToId());
bool startAnim = false; bool startAnim = false;
if (inRecord != _inRecord) { if (inRecord != _inRecord) {
_inRecord = inRecord; _inRecord = inRecord;
@ -4862,9 +5000,9 @@ void HistoryWidget::mouseMoveEvent(QMouseEvent *e) {
a_recordCancel.start(_inField ? st::recordCancel->c : st::recordCancelActive->c); a_recordCancel.start(_inField ? st::recordCancel->c : st::recordCancelActive->c);
startAnim = true; startAnim = true;
} }
if (inReply != _inReply) { if (inReplyEdit != _inReplyEdit) {
_inReply = inReply; _inReplyEdit = inReplyEdit;
setCursor(inReply ? style::cur_pointer : style::cur_default); setCursor(inReplyEdit ? style::cur_pointer : style::cur_default);
} }
if (startAnim) _a_record.start(); if (startAnim) _a_record.start();
} }
@ -5204,8 +5342,9 @@ void HistoryWidget::onKbToggle(bool manual) {
_field.setMaxHeight(st::maxFieldHeight); _field.setMaxHeight(st::maxFieldHeight);
_kbReplyTo = 0; _kbReplyTo = 0;
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_replyToId) { if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_editMsgId && !_replyToId) {
_replyForwardPreviewCancel.hide(); _fieldBarCancel.hide();
updateMouseTracking();
} }
} else { } else {
if (_history) { if (_history) {
@ -5223,10 +5362,11 @@ void HistoryWidget::onKbToggle(bool manual) {
_field.setMaxHeight(st::maxFieldHeight); _field.setMaxHeight(st::maxFieldHeight);
_kbReplyTo = (_peer->isChat() || _peer->isChannel() || _keyboard.forceReply()) ? App::histItemById(_keyboard.forMsgId()) : 0; _kbReplyTo = (_peer->isChat() || _peer->isChannel() || _keyboard.forceReply()) ? App::histItemById(_keyboard.forMsgId()) : 0;
if (_kbReplyTo && !_replyToId) { if (_kbReplyTo && !_editMsgId && !_replyToId) {
updateReplyToName(); updateReplyToName();
_replyToText.setText(st::msgFont, _kbReplyTo->inDialogsText(), _textDlgOptions); _replyEditMsgText.setText(st::msgFont, _kbReplyTo->inDialogsText(), _textDlgOptions);
_replyForwardPreviewCancel.show(); _fieldBarCancel.show();
updateMouseTracking();
} }
if (manual && _history) { if (manual && _history) {
_history->lastKeyboardHiddenId = 0; _history->lastKeyboardHiddenId = 0;
@ -5241,10 +5381,11 @@ void HistoryWidget::onKbToggle(bool manual) {
_field.setMaxHeight(st::maxFieldHeight - maxh); _field.setMaxHeight(st::maxFieldHeight - maxh);
_kbReplyTo = (_peer->isChat() || _peer->isChannel() || _keyboard.forceReply()) ? App::histItemById(_keyboard.forMsgId()) : 0; _kbReplyTo = (_peer->isChat() || _peer->isChannel() || _keyboard.forceReply()) ? App::histItemById(_keyboard.forMsgId()) : 0;
if (_kbReplyTo && !_replyToId) { if (_kbReplyTo && !_editMsgId && !_replyToId) {
updateReplyToName(); updateReplyToName();
_replyToText.setText(st::msgFont, _kbReplyTo->inDialogsText(), _textDlgOptions); _replyEditMsgText.setText(st::msgFont, _kbReplyTo->inDialogsText(), _textDlgOptions);
_replyForwardPreviewCancel.show(); _fieldBarCancel.show();
updateMouseTracking();
} }
if (manual && _history) { if (manual && _history) {
_history->lastKeyboardHiddenId = 0; _history->lastKeyboardHiddenId = 0;
@ -5414,7 +5555,7 @@ void HistoryWidget::onFieldResize() {
_kbScroll.setGeometry(0, height() - kbh, width(), kbh); _kbScroll.setGeometry(0, height() - kbh, width(), kbh);
} }
_field.move(_attachDocument.x() + _attachDocument.width(), height() - kbh - _field.height() - st::sendPadding); _field.move(_attachDocument.x() + _attachDocument.width(), height() - kbh - _field.height() - st::sendPadding);
_replyForwardPreviewCancel.move(width() - _replyForwardPreviewCancel.width(), _field.y() - st::sendPadding - _replyForwardPreviewCancel.height()); _fieldBarCancel.move(width() - _fieldBarCancel.width(), _field.y() - st::sendPadding - _fieldBarCancel.height());
_attachDocument.move(0, height() - kbh - _attachDocument.height()); _attachDocument.move(0, height() - kbh - _attachDocument.height());
_attachPhoto.move(_attachDocument.x(), _attachDocument.y()); _attachPhoto.move(_attachDocument.x(), _attachDocument.y());
@ -5454,12 +5595,18 @@ void HistoryWidget::onCheckMentionDropdown() {
} }
void HistoryWidget::updateFieldPlaceholder() { void HistoryWidget::updateFieldPlaceholder() {
if (_inlineBot && _inlineBot != InlineBotLookingUpData) { if (_editMsgId) {
_field.setPlaceholder(_inlineBot->botInfo->inlinePlaceholder.mid(1), _inlineBot->username.size() + 2); _field.setPlaceholder(lang(lng_edit_message_text));
} else if (hasBroadcastToggle()) { _send.setText(lang(lng_settings_save));
_field.setPlaceholder(lang(_broadcast.checked() ? lng_broadcast_ph : lng_comment_ph));
} else { } else {
_field.setPlaceholder(lang((_history && _history->isChannel() && !_history->isMegagroup()) ? (_peer->asChannel()->canPublish() ? lng_broadcast_ph : lng_comment_ph) : lng_message_ph)); if (_inlineBot && _inlineBot != InlineBotLookingUpData) {
_field.setPlaceholder(_inlineBot->botInfo->inlinePlaceholder.mid(1), _inlineBot->username.size() + 2);
} else if (hasBroadcastToggle()) {
_field.setPlaceholder(lang(_broadcast.checked() ? lng_broadcast_ph : lng_comment_ph));
} else {
_field.setPlaceholder(lang((_history && _history->isChannel() && !_history->isMegagroup()) ? (_peer->asChannel()->canPublish() ? lng_broadcast_ph : lng_comment_ph) : lng_message_ph));
}
_send.setText(lang(lng_send_button));
} }
} }
@ -5896,7 +6043,7 @@ void HistoryWidget::resizeEvent(QResizeEvent *e) {
_attachDocument.move(0, height() - kbh - _attachDocument.height()); _attachDocument.move(0, height() - kbh - _attachDocument.height());
_attachPhoto.move(_attachDocument.x(), _attachDocument.y()); _attachPhoto.move(_attachDocument.x(), _attachDocument.y());
_replyForwardPreviewCancel.move(width() - _replyForwardPreviewCancel.width(), _field.y() - st::sendPadding - _replyForwardPreviewCancel.height()); _fieldBarCancel.move(width() - _fieldBarCancel.width(), _field.y() - st::sendPadding - _fieldBarCancel.height());
updateListSize(App::main() ? App::main()->contentScrollAddToY() : 0); updateListSize(App::main() ? App::main()->contentScrollAddToY() : 0);
bool kbShowShown = _history && !_kbShown && _keyboard.hasMarkup(); bool kbShowShown = _history && !_kbShown && _keyboard.hasMarkup();
@ -5945,8 +6092,12 @@ void HistoryWidget::resizeEvent(QResizeEvent *e) {
void HistoryWidget::itemRemoved(HistoryItem *item) { void HistoryWidget::itemRemoved(HistoryItem *item) {
if (_list) _list->itemRemoved(item); if (_list) _list->itemRemoved(item);
if (item == _replyTo) { if (item == _replyEditMsg) {
cancelReply(); if (_editMsgId) {
cancelEdit();
} else {
cancelReply();
}
} }
if (item == _replyReturn) { if (item == _replyReturn) {
calcNextReplyReturn(); calcNextReplyReturn();
@ -5980,7 +6131,7 @@ void HistoryWidget::updateListSize(int32 addToY, bool initial, bool loadedDown,
if (_canSendMessages) { if (_canSendMessages) {
newScrollHeight -= (_field.height() + 2 * st::sendPadding); newScrollHeight -= (_field.height() + 2 * st::sendPadding);
} }
if (replyToId() || readyToForward() || (_previewData && _previewData->pendingTill >= 0)) { if (_editMsgId || replyToId() || readyToForward() || (_previewData && _previewData->pendingTill >= 0)) {
newScrollHeight -= st::replyHeight; newScrollHeight -= st::replyHeight;
} }
if (_kbShown) { if (_kbShown) {
@ -6163,22 +6314,22 @@ void HistoryWidget::updateBotKeyboard(History *h) {
bool changed = false; bool changed = false;
bool wasVisible = _kbShown || _kbReplyTo; bool wasVisible = _kbShown || _kbReplyTo;
if ((_replyToId && !_replyTo) || !_history) { if ((_replyToId && !_replyEditMsg) || _editMsgId || !_history) {
changed = _keyboard.updateMarkup(0); changed = _keyboard.updateMarkup(0);
} else if (_replyTo) { } else if (_replyToId && _replyEditMsg) {
changed = _keyboard.updateMarkup(_replyTo); changed = _keyboard.updateMarkup(_replyEditMsg);
} else { } else {
changed = _keyboard.updateMarkup(_history->lastKeyboardId ? App::histItemById(_channel, _history->lastKeyboardId) : 0); changed = _keyboard.updateMarkup(_history->lastKeyboardId ? App::histItemById(_channel, _history->lastKeyboardId) : 0);
} }
updateCmdStartShown(); updateCmdStartShown();
if (!changed) return; if (!changed) return;
bool hasMarkup = _keyboard.hasMarkup(), forceReply = _keyboard.forceReply() && !_replyTo; bool hasMarkup = _keyboard.hasMarkup(), forceReply = _keyboard.forceReply() && (!_replyToId || !_replyEditMsg);
if (hasMarkup || forceReply) { if (hasMarkup || forceReply) {
if (_keyboard.singleUse() && _keyboard.hasMarkup() && _keyboard.forMsgId() == FullMsgId(_channel, _history->lastKeyboardId) && _history->lastKeyboardUsed) { if (_keyboard.singleUse() && _keyboard.hasMarkup() && _keyboard.forMsgId() == FullMsgId(_channel, _history->lastKeyboardId) && _history->lastKeyboardUsed) {
_history->lastKeyboardHiddenId = _history->lastKeyboardId; _history->lastKeyboardHiddenId = _history->lastKeyboardId;
} }
if (!isBotStart() && !isBlocked() && _canSendMessages && (wasVisible || _replyTo || (!_field.hasSendText() && !kbWasHidden()))) { if (!isBotStart() && !isBlocked() && _canSendMessages && (wasVisible || (_replyToId && _replyEditMsg) || (!_field.hasSendText() && !kbWasHidden()))) {
if (!_a_show.animating()) { if (!_a_show.animating()) {
if (hasMarkup) { if (hasMarkup) {
_kbScroll.show(); _kbScroll.show();
@ -6198,8 +6349,9 @@ void HistoryWidget::updateBotKeyboard(History *h) {
_kbReplyTo = (_peer->isChat() || _peer->isChannel() || _keyboard.forceReply()) ? App::histItemById(_keyboard.forMsgId()) : 0; _kbReplyTo = (_peer->isChat() || _peer->isChannel() || _keyboard.forceReply()) ? App::histItemById(_keyboard.forMsgId()) : 0;
if (_kbReplyTo && !_replyToId) { if (_kbReplyTo && !_replyToId) {
updateReplyToName(); updateReplyToName();
_replyToText.setText(st::msgFont, _kbReplyTo->inDialogsText(), _textDlgOptions); _replyEditMsgText.setText(st::msgFont, _kbReplyTo->inDialogsText(), _textDlgOptions);
_replyForwardPreviewCancel.show(); _fieldBarCancel.show();
updateMouseTracking();
} }
} else { } else {
if (!_a_show.animating()) { if (!_a_show.animating()) {
@ -6213,7 +6365,8 @@ void HistoryWidget::updateBotKeyboard(History *h) {
_kbShown = false; _kbShown = false;
_kbReplyTo = 0; _kbReplyTo = 0;
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_replyToId) { if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_replyToId) {
_replyForwardPreviewCancel.hide(); _fieldBarCancel.hide();
updateMouseTracking();
} }
} }
} else { } else {
@ -6227,8 +6380,9 @@ void HistoryWidget::updateBotKeyboard(History *h) {
_field.setMaxHeight(st::maxFieldHeight); _field.setMaxHeight(st::maxFieldHeight);
_kbShown = false; _kbShown = false;
_kbReplyTo = 0; _kbReplyTo = 0;
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_replyToId) { if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_replyToId && !_editMsgId) {
_replyForwardPreviewCancel.hide(); _fieldBarCancel.hide();
updateMouseTracking();
} }
} }
resizeEvent(0); resizeEvent(0);
@ -6271,7 +6425,7 @@ void HistoryWidget::updateCollapseCommentsVisibility() {
void HistoryWidget::mousePressEvent(QMouseEvent *e) { void HistoryWidget::mousePressEvent(QMouseEvent *e) {
_replyForwardPressed = QRect(0, _field.y() - st::sendPadding - st::replyHeight, st::replySkip, st::replyHeight).contains(e->pos()); _replyForwardPressed = QRect(0, _field.y() - st::sendPadding - st::replyHeight, st::replySkip, st::replyHeight).contains(e->pos());
if (_replyForwardPressed && !_replyForwardPreviewCancel.isHidden()) { if (_replyForwardPressed && !_fieldBarCancel.isHidden()) {
updateField(); updateField();
} else if (_inRecord && cHasAudioCapture()) { } else if (_inRecord && cHasAudioCapture()) {
audioCapture()->start(); audioCapture()->start();
@ -6285,8 +6439,8 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
a_recordDown.start(1); a_recordDown.start(1);
a_recordOver.restart(); a_recordOver.restart();
_a_record.start(); _a_record.start();
} else if (_inReply) { } else if (_inReplyEdit) {
Ui::showPeerHistory(_peer, replyToId()); Ui::showPeerHistory(_peer, _editMsgId ? _editMsgId : replyToId());
} }
} }
@ -6615,16 +6769,25 @@ void HistoryWidget::onReplyToMessage() {
App::main()->cancelForwarding(); App::main()->cancelForwarding();
_replyTo = to; if (_editMsgId) {
_replyToId = to->id; if (!_history->msgDraft) {
_replyToText.setText(st::msgFont, _replyTo->inDialogsText(), _textDlgOptions); _history->setMsgDraft(new HistoryDraft(QString(), to->id, MessageCursor(), false));
} else {
_history->msgDraft->msgId = to->id;
}
} else {
_replyEditMsg = to;
_replyToId = to->id;
_replyEditMsgText.setText(st::msgFont, _replyEditMsg->inDialogsText(), _textDlgOptions);
updateBotKeyboard(); updateBotKeyboard();
if (!_field.isHidden()) _replyForwardPreviewCancel.show(); if (!_field.isHidden()) _fieldBarCancel.show();
updateReplyToName(); updateMouseTracking();
resizeEvent(0); updateReplyToName();
updateField(); resizeEvent(0);
updateField();
}
_saveDraftText = true; _saveDraftText = true;
_saveDraftStart = getms(); _saveDraftStart = getms();
@ -6642,7 +6805,42 @@ void HistoryWidget::onEditMessage() {
Ui::showLayer(box); Ui::showLayer(box);
} else { } else {
delete box; delete box;
// edit post
if (_replyToId || !_field.getLastText().isEmpty()) {
_history->setMsgDraft(new HistoryDraft(_field, _replyToId, _previewCancelled));
} else {
_history->setMsgDraft(Nil);
}
QString text(textApplyEntities(to->originalText(), to->originalEntities()));
_history->setEditDraft(new HistoryEditDraft(text, to->id, MessageCursor(text.size(), text.size(), QFIXED_MAX), false));
applyDraft(false);
_previewData = 0;
if (HistoryMedia *media = to->getMedia()) {
if (media->type() == MediaTypeWebPage) {
_previewData = static_cast<HistoryWebPage*>(media)->webpage();
updatePreview();
}
}
if (!_previewData) {
onPreviewParse();
}
updateBotKeyboard();
if (!_field.isHidden()) _fieldBarCancel.show();
updateFieldPlaceholder();
updateMouseTracking();
updateReplyToName();
resizeEvent(0);
updateField();
_saveDraftText = true;
_saveDraftStart = getms();
onDraftSave();
_field.setFocus();
} }
} }
@ -6652,37 +6850,77 @@ bool HistoryWidget::lastForceReplyReplied(const FullMsgId &replyTo) const {
} }
void HistoryWidget::cancelReply(bool lastKeyboardUsed) { void HistoryWidget::cancelReply(bool lastKeyboardUsed) {
bool wasReply = _replyToId || (_history && _history->msgDraft && _history->msgDraft->msgId);
if (_replyToId) { if (_replyToId) {
_replyTo = 0; _replyEditMsg = 0;
_replyToId = 0; _replyToId = 0;
mouseMoveEvent(0); mouseMoveEvent(0);
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_kbReplyTo) { if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_kbReplyTo) {
_replyForwardPreviewCancel.hide(); _fieldBarCancel.hide();
updateMouseTracking();
} }
updateBotKeyboard(); updateBotKeyboard();
resizeEvent(0); resizeEvent(0);
update(); update();
} else if (wasReply) {
if (_history->msgDraft->text.isEmpty()) {
_history->setMsgDraft(Nil);
} else {
_history->msgDraft->msgId = 0;
}
}
if (wasReply) {
_saveDraftText = true; _saveDraftText = true;
_saveDraftStart = getms(); _saveDraftStart = getms();
onDraftSave(); onDraftSave();
} }
if (_keyboard.singleUse() && _keyboard.forceReply() && lastKeyboardUsed) { if (!_editMsgId && _keyboard.singleUse() && _keyboard.forceReply() && lastKeyboardUsed) {
if (_kbReplyTo) { if (_kbReplyTo) {
onKbToggle(false); onKbToggle(false);
} }
} }
} }
void HistoryWidget::cancelEdit() {
if (!_editMsgId) return;
_editMsgId = 0;
_replyEditMsg = 0;
_history->setEditDraft(Nil);
applyDraft();
if (_saveEditMsgRequestId) {
MTP::cancel(_saveEditMsgRequestId);
_saveEditMsgRequestId = 0;
}
_saveDraftText = true;
_saveDraftStart = getms();
onDraftSave();
mouseMoveEvent(0);
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !replyToId()) {
_fieldBarCancel.hide();
updateMouseTracking();
}
onTextChange();
updateBotKeyboard();
updateFieldPlaceholder();
resizeEvent(0);
update();
}
void HistoryWidget::cancelForwarding() { void HistoryWidget::cancelForwarding() {
updateControlsVisibility(); updateControlsVisibility();
resizeEvent(0); resizeEvent(0);
update(); update();
} }
void HistoryWidget::onReplyForwardPreviewCancel() { void HistoryWidget::onFieldBarCancel() {
_replyForwardPressed = false; _replyForwardPressed = false;
if (_previewData && _previewData->pendingTill >= 0) { if (_previewData && _previewData->pendingTill >= 0) {
_previewCancelled = true; _previewCancelled = true;
@ -6691,6 +6929,8 @@ void HistoryWidget::onReplyForwardPreviewCancel() {
_saveDraftText = true; _saveDraftText = true;
_saveDraftStart = getms(); _saveDraftStart = getms();
onDraftSave(); onDraftSave();
} else if (_editMsgId) {
cancelEdit();
} else if (readyToForward()) { } else if (readyToForward()) {
App::main()->cancelForwarding(); App::main()->cancelForwarding();
} else if (_replyToId) { } else if (_replyToId) {
@ -6717,7 +6957,10 @@ void HistoryWidget::previewCancel() {
_previewData = 0; _previewData = 0;
_previewLinks.clear(); _previewLinks.clear();
updatePreview(); updatePreview();
if (!_replyToId && !readyToForward() && !_kbReplyTo) _replyForwardPreviewCancel.hide(); if (!_editMsgId && !_replyToId && !readyToForward() && !_kbReplyTo) {
_fieldBarCancel.hide();
updateMouseTracking();
}
} }
void HistoryWidget::onPreviewParse() { void HistoryWidget::onPreviewParse() {
@ -6781,7 +7024,8 @@ void HistoryWidget::gotPreview(QString links, const MTPMessageMedia &result, mtp
void HistoryWidget::updatePreview() { void HistoryWidget::updatePreview() {
_previewTimer.stop(); _previewTimer.stop();
if (_previewData && _previewData->pendingTill >= 0) { if (_previewData && _previewData->pendingTill >= 0) {
_replyForwardPreviewCancel.show(); _fieldBarCancel.show();
updateMouseTracking();
if (_previewData->pendingTill) { if (_previewData->pendingTill) {
_previewTitle.setText(st::msgServiceNameFont, lang(lng_preview_loading), _textNameOptions); _previewTitle.setText(st::msgServiceNameFont, lang(lng_preview_loading), _textNameOptions);
_previewDescription.setText(st::msgFont, _previewLinks.splitRef(' ').at(0).toString(), _textDlgOptions); _previewDescription.setText(st::msgFont, _previewLinks.splitRef(' ').at(0).toString(), _textDlgOptions);
@ -6818,8 +7062,9 @@ void HistoryWidget::updatePreview() {
_previewTitle.setText(st::msgServiceNameFont, title, _textNameOptions); _previewTitle.setText(st::msgServiceNameFont, title, _textNameOptions);
_previewDescription.setText(st::msgFont, desc, _textDlgOptions); _previewDescription.setText(st::msgFont, desc, _textDlgOptions);
} }
} else if (!readyToForward() && !replyToId()) { } else if (!readyToForward() && !replyToId() && !_editMsgId) {
_replyForwardPreviewCancel.hide(); _fieldBarCancel.hide();
updateMouseTracking();
} }
resizeEvent(0); resizeEvent(0);
update(); update();
@ -7035,19 +7280,28 @@ void HistoryWidget::updateTopBarSelection() {
update(); update();
} }
void HistoryWidget::updateReplyTo(bool force) { void HistoryWidget::updateReplyEditTexts(bool force) {
if (!_replyToId || _replyTo) return; if (_replyEditMsg || (!_editMsgId && !_replyToId)) {
_replyTo = App::histItemById(_channel, _replyToId); return;
if (_replyTo) { }
_replyToText.setText(st::msgFont, _replyTo->inDialogsText(), _textDlgOptions); _replyEditMsg = App::histItemById(_channel, _editMsgId ? _editMsgId : _replyToId);
if (_replyEditMsg) {
_replyEditMsgText.setText(st::msgFont, _replyEditMsg->inDialogsText(), _textDlgOptions);
updateBotKeyboard(); updateBotKeyboard();
if (!_field.isHidden() || _recording) _replyForwardPreviewCancel.show(); if (!_field.isHidden() || _recording) {
_fieldBarCancel.show();
updateMouseTracking();
}
updateReplyToName(); updateReplyToName();
updateField(); updateField();
} else if (force) { } else if (force) {
cancelReply(); if (_editMsgId) {
cancelEdit();
} else {
cancelReply();
}
} }
} }
@ -7061,9 +7315,10 @@ void HistoryWidget::updateForwarding(bool force) {
} }
void HistoryWidget::updateReplyToName() { void HistoryWidget::updateReplyToName() {
if (!_replyTo && (_replyToId || !_kbReplyTo)) return; if (_editMsgId) return;
_replyToName.setText(st::msgServiceNameFont, App::peerName((_replyTo ? _replyTo : _kbReplyTo)->author()), _textNameOptions); if (!_replyEditMsg && (_replyToId || !_kbReplyTo)) return;
_replyToNameVersion = (_replyTo ? _replyTo : _kbReplyTo)->author()->nameVersion; _replyToName.setText(st::msgServiceNameFont, App::peerName((_replyEditMsg ? _replyEditMsg : _kbReplyTo)->author()), _textNameOptions);
_replyToNameVersion = (_replyEditMsg ? _replyEditMsg : _kbReplyTo)->author()->nameVersion;
} }
void HistoryWidget::updateField() { void HistoryWidget::updateField() {
@ -7076,9 +7331,9 @@ void HistoryWidget::drawField(Painter &p) {
Text *from = 0, *text = 0; Text *from = 0, *text = 0;
bool serviceColor = false, hasForward = readyToForward(); bool serviceColor = false, hasForward = readyToForward();
ImagePtr preview; ImagePtr preview;
HistoryItem *drawReplyTo = _replyToId ? _replyTo : _kbReplyTo; HistoryItem *drawMsgText = (_editMsgId || _replyToId) ? _replyEditMsg : _kbReplyTo;
if (_replyToId || (!hasForward && _kbReplyTo)) { if (_editMsgId || _replyToId || (!hasForward && _kbReplyTo)) {
if (drawReplyTo && drawReplyTo->author()->nameVersion > _replyToNameVersion) { if (!_editMsgId && drawMsgText && drawMsgText->author()->nameVersion > _replyToNameVersion) {
updateReplyToName(); updateReplyToName();
} }
backy -= st::replyHeight; backy -= st::replyHeight;
@ -7093,27 +7348,32 @@ void HistoryWidget::drawField(Painter &p) {
} }
bool drawPreview = (_previewData && _previewData->pendingTill >= 0) && !_replyForwardPressed; bool drawPreview = (_previewData && _previewData->pendingTill >= 0) && !_replyForwardPressed;
p.fillRect(0, backy, width(), backh, st::taMsgField.bgColor->b); p.fillRect(0, backy, width(), backh, st::taMsgField.bgColor->b);
if (_replyToId || (!hasForward && _kbReplyTo)) { if (_editMsgId || _replyToId || (!hasForward && _kbReplyTo)) {
int32 replyLeft = st::replySkip; int32 replyLeft = st::replySkip;
p.drawPixmap(QPoint(st::replyIconPos.x(), backy + st::replyIconPos.y()), App::sprite(), st::replyIcon); p.drawPixmap(QPoint(st::replyIconPos.x(), backy + st::replyIconPos.y()), App::sprite(), _editMsgId ? st::editIcon : st::replyIcon);
if (!drawPreview) { if (!drawPreview) {
if (drawReplyTo) { if (drawMsgText) {
if (drawReplyTo->getMedia() && drawReplyTo->getMedia()->hasReplyPreview()) { if (drawMsgText->getMedia() && drawMsgText->getMedia()->hasReplyPreview()) {
ImagePtr replyPreview = drawReplyTo->getMedia()->replyPreview(); ImagePtr replyPreview = drawMsgText->getMedia()->replyPreview();
if (!replyPreview->isNull()) { if (!replyPreview->isNull()) {
QRect to(replyLeft, backy + st::msgReplyPadding.top(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height()); QRect to(replyLeft, backy + st::msgReplyPadding.top(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height());
p.drawPixmap(to.x(), to.y(), replyPreview->pixSingle(replyPreview->width() / cIntRetinaFactor(), replyPreview->height() / cIntRetinaFactor(), to.width(), to.height())); p.drawPixmap(to.x(), to.y(), replyPreview->pixSingle(replyPreview->width() / cIntRetinaFactor(), replyPreview->height() / cIntRetinaFactor(), to.width(), to.height()));
} }
replyLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x(); replyLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x();
} }
p.setPen(st::replyColor->p); p.setPen(st::replyColor);
_replyToName.drawElided(p, replyLeft, backy + st::msgReplyPadding.top(), width() - replyLeft - _replyForwardPreviewCancel.width() - st::msgReplyPadding.right()); if (_editMsgId) {
p.setPen((((drawReplyTo->toHistoryMessage() && drawReplyTo->toHistoryMessage()->emptyText()) || drawReplyTo->serviceMsg()) ? st::msgInDateFg : st::msgColor)->p); p.setFont(st::msgServiceNameFont);
_replyToText.drawElided(p, replyLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - replyLeft - _replyForwardPreviewCancel.width() - st::msgReplyPadding.right()); p.drawText(replyLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->ascent, lang(lng_edit_message));
} else {
_replyToName.drawElided(p, replyLeft, backy + st::msgReplyPadding.top(), width() - replyLeft - _fieldBarCancel.width() - st::msgReplyPadding.right());
}
p.setPen((((drawMsgText->toHistoryMessage() && drawMsgText->toHistoryMessage()->emptyText()) || drawMsgText->serviceMsg()) ? st::msgInDateFg : st::msgColor)->p);
_replyEditMsgText.drawElided(p, replyLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - replyLeft - _fieldBarCancel.width() - st::msgReplyPadding.right());
} else { } else {
p.setFont(st::msgDateFont->f); p.setFont(st::msgDateFont->f);
p.setPen(st::msgInDateFg->p); p.setPen(st::msgInDateFg->p);
p.drawText(replyLeft, backy + st::msgReplyPadding.top() + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(lang(lng_profile_loading), width() - replyLeft - _replyForwardPreviewCancel.width() - st::msgReplyPadding.right())); p.drawText(replyLeft, backy + st::msgReplyPadding.top() + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(lang(lng_profile_loading), width() - replyLeft - _fieldBarCancel.width() - st::msgReplyPadding.right()));
} }
} }
} else if (from && text) { } else if (from && text) {
@ -7131,9 +7391,9 @@ void HistoryWidget::drawField(Painter &p) {
forwardLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x(); forwardLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x();
} }
p.setPen(st::replyColor->p); p.setPen(st::replyColor->p);
from->drawElided(p, forwardLeft, backy + st::msgReplyPadding.top(), width() - forwardLeft - _replyForwardPreviewCancel.width() - st::msgReplyPadding.right()); from->drawElided(p, forwardLeft, backy + st::msgReplyPadding.top(), width() - forwardLeft - _fieldBarCancel.width() - st::msgReplyPadding.right());
p.setPen((serviceColor ? st::msgInDateFg : st::msgColor)->p); p.setPen((serviceColor ? st::msgInDateFg : st::msgColor)->p);
text->drawElided(p, forwardLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - forwardLeft - _replyForwardPreviewCancel.width() - st::msgReplyPadding.right()); text->drawElided(p, forwardLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - forwardLeft - _fieldBarCancel.width() - st::msgReplyPadding.right());
} }
} }
if (drawPreview) { if (drawPreview) {
@ -7153,9 +7413,9 @@ void HistoryWidget::drawField(Painter &p) {
previewLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x(); previewLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x();
} }
p.setPen(st::replyColor->p); p.setPen(st::replyColor->p);
_previewTitle.drawElided(p, previewLeft, backy + st::msgReplyPadding.top(), width() - previewLeft - _replyForwardPreviewCancel.width() - st::msgReplyPadding.right()); _previewTitle.drawElided(p, previewLeft, backy + st::msgReplyPadding.top(), width() - previewLeft - _fieldBarCancel.width() - st::msgReplyPadding.right());
p.setPen(st::msgColor->p); p.setPen(st::msgColor->p);
_previewDescription.drawElided(p, previewLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - previewLeft - _replyForwardPreviewCancel.width() - st::msgReplyPadding.right()); _previewDescription.drawElided(p, previewLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - previewLeft - _fieldBarCancel.width() - st::msgReplyPadding.right());
} }
} }

View File

@ -505,9 +505,10 @@ public:
void updateScrollColors(); void updateScrollColors();
MsgId replyToId() const; MsgId replyToId() const;
void updateReplyTo(bool force = false); void updateReplyEditTexts(bool force = false);
bool lastForceReplyReplied(const FullMsgId &replyTo = FullMsgId(NoChannel, -1)) const; bool lastForceReplyReplied(const FullMsgId &replyTo = FullMsgId(NoChannel, -1)) const;
void cancelReply(bool lastKeyboardUsed = false); void cancelReply(bool lastKeyboardUsed = false);
void cancelEdit();
void updateForwarding(bool force = false); void updateForwarding(bool force = false);
void cancelForwarding(); // called by MainWidget void cancelForwarding(); // called by MainWidget
@ -595,7 +596,7 @@ public slots:
void onCancel(); void onCancel();
void onReplyToMessage(); void onReplyToMessage();
void onEditMessage(); void onEditMessage();
void onReplyForwardPreviewCancel(); void onFieldBarCancel();
void onCancelSendAction(); void onCancelSendAction();
@ -689,12 +690,17 @@ public slots:
private: private:
MsgId _replyToId; MsgId _replyToId;
HistoryItem *_replyTo; Text _replyToName;
Text _replyToName, _replyToText;
int32 _replyToNameVersion; int32 _replyToNameVersion;
IconedButton _replyForwardPreviewCancel;
void updateReplyToName(); void updateReplyToName();
MsgId _editMsgId;
HistoryItem *_replyEditMsg;
Text _replyEditMsgText;
IconedButton _fieldBarCancel;
void sendExistingDocument(DocumentData *doc, const QString &caption); void sendExistingDocument(DocumentData *doc, const QString &caption);
void sendExistingPhoto(PhotoData *photo, const QString &caption); void sendExistingPhoto(PhotoData *photo, const QString &caption);
@ -702,6 +708,13 @@ private:
void drawRecordButton(Painter &p); void drawRecordButton(Painter &p);
void drawRecording(Painter &p); void drawRecording(Painter &p);
void updateMouseTracking();
mtpRequestId _saveEditMsgRequestId;
void saveEditMsg();
void saveEditMsgDone(History *history, const MTPUpdates &updates, mtpRequestId req);
bool saveEditMsgFail(History *history, const RPCError &error, mtpRequestId req);
DBIPeerReportSpamStatus _reportSpamStatus; DBIPeerReportSpamStatus _reportSpamStatus;
void updateReportSpamStatus(); void updateReportSpamStatus();
@ -747,7 +760,8 @@ private:
void savedGifsGot(const MTPmessages_SavedGifs &gifs); void savedGifsGot(const MTPmessages_SavedGifs &gifs);
bool savedGifsFailed(const RPCError &error); bool savedGifsFailed(const RPCError &error);
void writeDraft(MsgId *replyTo = 0, const QString *text = 0, const MessageCursor *cursor = 0, bool *previewCancelled = 0); void writeDrafts(HistoryDraft **msgDraft, HistoryEditDraft **editDraft);
void writeDrafts(History *history);
void setFieldText(const QString &text, int32 textUpdateEventsFlags = 0, bool clearUndoHistory = true); void setFieldText(const QString &text, int32 textUpdateEventsFlags = 0, bool clearUndoHistory = true);
QStringList getMediasFromMime(const QMimeData *d); QStringList getMediasFromMime(const QMimeData *d);
@ -806,7 +820,7 @@ private:
bool _cmdStartShown; bool _cmdStartShown;
MessageField _field; MessageField _field;
Animation _a_record, _a_recording; Animation _a_record, _a_recording;
bool _recording, _inRecord, _inField, _inReply; bool _recording, _inRecord, _inField, _inReplyEdit;
anim::ivalue a_recordingLevel; anim::ivalue a_recordingLevel;
int32 _recordingSamples; int32 _recordingSamples;
anim::fvalue a_recordOver, a_recordDown; anim::fvalue a_recordOver, a_recordDown;

View File

@ -557,7 +557,7 @@ namespace {
}; };
typedef QMap<PeerId, FileKey> DraftsMap; typedef QMap<PeerId, FileKey> DraftsMap;
DraftsMap _draftsMap, _draftsPositionsMap; DraftsMap _draftsMap, _draftCursorsMap;
typedef QMap<PeerId, bool> DraftsNotReadMap; typedef QMap<PeerId, bool> DraftsNotReadMap;
DraftsNotReadMap _draftsNotReadMap; DraftsNotReadMap _draftsNotReadMap;
@ -1672,7 +1672,7 @@ namespace {
} }
LOG(("App Info: reading encrypted map..")); LOG(("App Info: reading encrypted map.."));
DraftsMap draftsMap, draftsPositionsMap; DraftsMap draftsMap, draftCursorsMap;
DraftsNotReadMap draftsNotReadMap; DraftsNotReadMap draftsNotReadMap;
StorageMap imagesMap, stickerImagesMap, audiosMap; StorageMap imagesMap, stickerImagesMap, audiosMap;
qint64 storageImagesSize = 0, storageStickersSize = 0, storageAudiosSize = 0; qint64 storageImagesSize = 0, storageStickersSize = 0, storageAudiosSize = 0;
@ -1701,7 +1701,7 @@ namespace {
FileKey key; FileKey key;
quint64 p; quint64 p;
map.stream >> key >> p; map.stream >> key >> p;
draftsPositionsMap.insert(p, key); draftCursorsMap.insert(p, key);
} }
} break; } break;
case lskImages: { case lskImages: {
@ -1781,7 +1781,7 @@ namespace {
} }
_draftsMap = draftsMap; _draftsMap = draftsMap;
_draftsPositionsMap = draftsPositionsMap; _draftCursorsMap = draftCursorsMap;
_draftsNotReadMap = draftsNotReadMap; _draftsNotReadMap = draftsNotReadMap;
_imagesMap = imagesMap; _imagesMap = imagesMap;
@ -1860,7 +1860,7 @@ namespace {
uint32 mapSize = 0; uint32 mapSize = 0;
if (!_draftsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftsMap.size() * sizeof(quint64) * 2; if (!_draftsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftsMap.size() * sizeof(quint64) * 2;
if (!_draftsPositionsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftsPositionsMap.size() * sizeof(quint64) * 2; if (!_draftCursorsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftCursorsMap.size() * sizeof(quint64) * 2;
if (!_imagesMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _imagesMap.size() * (sizeof(quint64) * 3 + sizeof(qint32)); if (!_imagesMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _imagesMap.size() * (sizeof(quint64) * 3 + sizeof(qint32));
if (!_stickerImagesMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _stickerImagesMap.size() * (sizeof(quint64) * 3 + sizeof(qint32)); if (!_stickerImagesMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _stickerImagesMap.size() * (sizeof(quint64) * 3 + sizeof(qint32));
if (!_audiosMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _audiosMap.size() * (sizeof(quint64) * 3 + sizeof(qint32)); if (!_audiosMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _audiosMap.size() * (sizeof(quint64) * 3 + sizeof(qint32));
@ -1880,9 +1880,9 @@ namespace {
mapData.stream << quint64(i.value()) << quint64(i.key()); mapData.stream << quint64(i.value()) << quint64(i.key());
} }
} }
if (!_draftsPositionsMap.isEmpty()) { if (!_draftCursorsMap.isEmpty()) {
mapData.stream << quint32(lskDraftPosition) << quint32(_draftsPositionsMap.size()); mapData.stream << quint32(lskDraftPosition) << quint32(_draftCursorsMap.size());
for (DraftsMap::const_iterator i = _draftsPositionsMap.cbegin(), e = _draftsPositionsMap.cend(); i != e; ++i) { for (DraftsMap::const_iterator i = _draftCursorsMap.cbegin(), e = _draftCursorsMap.cend(); i != e; ++i) {
mapData.stream << quint64(i.value()) << quint64(i.key()); mapData.stream << quint64(i.value()) << quint64(i.key());
} }
} }
@ -2180,7 +2180,7 @@ namespace Local {
_passKeySalt.clear(); // reset passcode, local key _passKeySalt.clear(); // reset passcode, local key
_draftsMap.clear(); _draftsMap.clear();
_draftsPositionsMap.clear(); _draftCursorsMap.clear();
_fileLocations.clear(); _fileLocations.clear();
_fileLocationPairs.clear(); _fileLocationPairs.clear();
_fileLocationAliases.clear(); _fileLocationAliases.clear();
@ -2237,10 +2237,10 @@ namespace Local {
return _oldSettingsVersion; return _oldSettingsVersion;
} }
void writeDraft(const PeerId &peer, const MessageDraft &draft) { void writeDrafts(const PeerId &peer, const MessageDraft &msgDraft, const MessageDraft &editDraft) {
if (!_working()) return; if (!_working()) return;
if (draft.replyTo <= 0 && draft.text.isEmpty()) { if (msgDraft.msgId <= 0 && msgDraft.text.isEmpty() && editDraft.msgId <= 0) {
DraftsMap::iterator i = _draftsMap.find(peer); DraftsMap::iterator i = _draftsMap.find(peer);
if (i != _draftsMap.cend()) { if (i != _draftsMap.cend()) {
clearKey(i.value()); clearKey(i.value());
@ -2257,8 +2257,12 @@ namespace Local {
_mapChanged = true; _mapChanged = true;
_writeMap(WriteMapFast); _writeMap(WriteMapFast);
} }
EncryptedDescriptor data(sizeof(quint64) + _stringSize(draft.text) + sizeof(qint32));
data.stream << quint64(peer) << draft.text << qint32(draft.replyTo) << qint32(draft.previewCancelled ? 1 : 0); EncryptedDescriptor data(sizeof(quint64) + _stringSize(msgDraft.text) + 2 * sizeof(qint32) + _stringSize(editDraft.text) + 2 * sizeof(qint32));
data.stream << quint64(peer);
data.stream << msgDraft.text << qint32(msgDraft.msgId) << qint32(msgDraft.previewCancelled ? 1 : 0);
data.stream << editDraft.text << qint32(editDraft.msgId) << qint32(editDraft.previewCancelled ? 1 : 0);
FileWriteDescriptor file(i.value()); FileWriteDescriptor file(i.value());
file.writeEncrypted(data); file.writeEncrypted(data);
@ -2266,75 +2270,123 @@ namespace Local {
} }
} }
MessageDraft readDraft(const PeerId &peer) { void clearDraftCursors(const PeerId &peer) {
if (!_draftsNotReadMap.remove(peer)) return MessageDraft(); DraftsMap::iterator i = _draftCursorsMap.find(peer);
if (i != _draftCursorsMap.cend()) {
clearKey(i.value());
_draftCursorsMap.erase(i);
_mapChanged = true;
_writeMap();
}
}
void _readDraftCursors(const PeerId &peer, MessageCursor &msgCursor, MessageCursor &editCursor) {
DraftsMap::iterator j = _draftCursorsMap.find(peer);
if (j == _draftCursorsMap.cend()) {
return;
}
FileReadDescriptor draft;
if (!readEncryptedFile(draft, j.value())) {
clearDraftCursors(peer);
return;
}
quint64 draftPeer;
qint32 msgPosition = 0, msgAnchor = 0, msgScroll = QFIXED_MAX;
qint32 editPosition = 0, editAnchor = 0, editScroll = QFIXED_MAX;
draft.stream >> draftPeer >> msgPosition >> msgAnchor >> msgScroll;
if (!draft.stream.atEnd()) {
draft.stream >> editPosition >> editAnchor >> editScroll;
}
if (draftPeer != peer) {
clearDraftCursors(peer);
return;
}
msgCursor = MessageCursor(msgPosition, msgAnchor, msgScroll);
editCursor = MessageCursor(editPosition, editAnchor, editScroll);
}
void readDraftsWithCursors(History *h) {
PeerId peer = h->peer->id;
if (!_draftsNotReadMap.remove(peer)) {
clearDraftCursors(peer);
return;
}
DraftsMap::iterator j = _draftsMap.find(peer); DraftsMap::iterator j = _draftsMap.find(peer);
if (j == _draftsMap.cend()) { if (j == _draftsMap.cend()) {
return MessageDraft(); clearDraftCursors(peer);
return;
} }
FileReadDescriptor draft; FileReadDescriptor draft;
if (!readEncryptedFile(draft, j.value())) { if (!readEncryptedFile(draft, j.value())) {
clearKey(j.value()); clearKey(j.value());
_draftsMap.erase(j); _draftsMap.erase(j);
return MessageDraft(); clearDraftCursors(peer);
return;
} }
quint64 draftPeer; quint64 draftPeer = 0;
QString draftText; QString msgText, editText;
qint32 draftReplyTo = 0, draftPreviewCancelled = 0; qint32 msgReplyTo = 0, msgPreviewCancelled = 0, editMsgId = 0, editPreviewCancelled = 0;
draft.stream >> draftPeer >> draftText; draft.stream >> draftPeer >> msgText;
if (draft.version >= 7021) draft.stream >> draftReplyTo; if (draft.version >= 7021) {
if (draft.version >= 8001) draft.stream >> draftPreviewCancelled; draft.stream >> msgReplyTo;
return (draftPeer == peer) ? MessageDraft(MsgId(draftReplyTo), draftText, (draftPreviewCancelled == 1)) : MessageDraft(); if (draft.version >= 8001) {
draft.stream >> msgPreviewCancelled;
if (!draft.stream.atEnd()) {
draft.stream >> editText >> editMsgId >> editPreviewCancelled;
}
}
}
if (draftPeer != peer) {
clearKey(j.value());
_draftsMap.erase(j);
clearDraftCursors(peer);
return;
}
MessageCursor msgCursor, editCursor;
_readDraftCursors(peer, msgCursor, editCursor);
if (msgText.isEmpty() && !msgReplyTo) {
h->setMsgDraft(Nil);
} else {
h->setMsgDraft(new HistoryDraft(msgText, msgReplyTo, msgCursor, msgPreviewCancelled));
}
if (!editMsgId) {
h->setEditDraft(Nil);
} else {
h->setEditDraft(new HistoryEditDraft(editText, editMsgId, editCursor, editPreviewCancelled));
}
} }
void writeDraftPositions(const PeerId &peer, const MessageCursor &cur) { void writeDraftCursors(const PeerId &peer, const MessageCursor &msgCursor, const MessageCursor &editCursor) {
if (!_working()) return; if (!_working()) return;
if (cur.position == 0 && cur.anchor == 0 && cur.scroll == QFIXED_MAX) { if (msgCursor == MessageCursor() && editCursor == MessageCursor()) {
DraftsMap::iterator i = _draftsPositionsMap.find(peer); clearDraftCursors(peer);
if (i != _draftsPositionsMap.cend()) {
clearKey(i.value());
_draftsPositionsMap.erase(i);
_mapChanged = true;
_writeMap();
}
} else { } else {
DraftsMap::const_iterator i = _draftsPositionsMap.constFind(peer); DraftsMap::const_iterator i = _draftCursorsMap.constFind(peer);
if (i == _draftsPositionsMap.cend()) { if (i == _draftCursorsMap.cend()) {
i = _draftsPositionsMap.insert(peer, genKey()); i = _draftCursorsMap.insert(peer, genKey());
_mapChanged = true; _mapChanged = true;
_writeMap(WriteMapFast); _writeMap(WriteMapFast);
} }
EncryptedDescriptor data(sizeof(quint64) + sizeof(qint32) * 3); EncryptedDescriptor data(sizeof(quint64) + sizeof(qint32) * 3);
data.stream << quint64(peer) << qint32(cur.position) << qint32(cur.anchor) << qint32(cur.scroll); data.stream << quint64(peer) << qint32(msgCursor.position) << qint32(msgCursor.anchor) << qint32(msgCursor.scroll);
data.stream << qint32(editCursor.position) << qint32(editCursor.anchor) << qint32(editCursor.scroll);
FileWriteDescriptor file(i.value()); FileWriteDescriptor file(i.value());
file.writeEncrypted(data); file.writeEncrypted(data);
} }
} }
MessageCursor readDraftPositions(const PeerId &peer) { bool hasDraftCursors(const PeerId &peer) {
DraftsMap::iterator j = _draftsPositionsMap.find(peer); return (_draftCursorsMap.constFind(peer) != _draftCursorsMap.cend());
if (j == _draftsPositionsMap.cend()) {
return MessageCursor();
}
FileReadDescriptor draft;
if (!readEncryptedFile(draft, j.value())) {
clearKey(j.value());
_draftsPositionsMap.erase(j);
return MessageCursor();
}
quint64 draftPeer;
qint32 curPosition, curAnchor, curScroll;
draft.stream >> draftPeer >> curPosition >> curAnchor >> curScroll;
return (draftPeer == peer) ? MessageCursor(curPosition, curAnchor, curScroll) : MessageCursor();
}
bool hasDraftPositions(const PeerId &peer) {
return (_draftsPositionsMap.constFind(peer) != _draftsPositionsMap.cend());
} }
void writeFileLocation(MediaKey location, const FileLocation &local) { void writeFileLocation(MediaKey location, const FileLocation &local) {
@ -3795,8 +3847,8 @@ namespace Local {
_draftsMap.clear(); _draftsMap.clear();
_mapChanged = true; _mapChanged = true;
} }
if (!_draftsPositionsMap.isEmpty()) { if (!_draftCursorsMap.isEmpty()) {
_draftsPositionsMap.clear(); _draftCursorsMap.clear();
_mapChanged = true; _mapChanged = true;
} }
if (_locationsKey) { if (_locationsKey) {

View File

@ -106,17 +106,16 @@ namespace Local {
int32 oldSettingsVersion(); int32 oldSettingsVersion();
struct MessageDraft { struct MessageDraft {
MessageDraft(MsgId replyTo = 0, QString text = QString(), bool previewCancelled = false) : replyTo(replyTo), text(text), previewCancelled(previewCancelled) { MessageDraft(MsgId msgId = 0, QString text = QString(), bool previewCancelled = false) : msgId(msgId), text(text), previewCancelled(previewCancelled) {
} }
MsgId replyTo; MsgId msgId;
QString text; QString text;
bool previewCancelled; bool previewCancelled;
}; };
void writeDraft(const PeerId &peer, const MessageDraft &draft); void writeDrafts(const PeerId &peer, const MessageDraft &msgDraft, const MessageDraft &editDraft);
MessageDraft readDraft(const PeerId &peer); void readDraftsWithCursors(History *h);
void writeDraftPositions(const PeerId &peer, const MessageCursor &cur); void writeDraftCursors(const PeerId &peer, const MessageCursor &msgCursor, const MessageCursor &editCursor);
MessageCursor readDraftPositions(const PeerId &peer); bool hasDraftCursors(const PeerId &peer);
bool hasDraftPositions(const PeerId &peer);
void writeFileLocation(MediaKey location, const FileLocation &local); void writeFileLocation(MediaKey location, const FileLocation &local);
FileLocation readFileLocation(MediaKey location, bool check = true); FileLocation readFileLocation(MediaKey location, bool check = true);

View File

@ -516,10 +516,8 @@ bool MainWidget::onShareUrl(const PeerId &peer, const QString &url, const QStrin
return false; return false;
} }
History *h = App::history(peer); History *h = App::history(peer);
h->draft = url + '\n' + text; h->setMsgDraft(new HistoryDraft(url + '\n' + text, 0, MessageCursor(url.size() + 1, url.size() + 1 + text.size(), QFIXED_MAX), false));
h->draftCursor.anchor = url.size() + 1; h->setEditDraft(Nil);
h->draftCursor.position = h->draftCursor.anchor + text.size();
h->draftPreviewCancelled = false;
bool opened = history.peer() && (history.peer()->id == peer); bool opened = history.peer() && (history.peer()->id == peer);
if (opened) { if (opened) {
history.applyDraft(); history.applyDraft();
@ -2039,7 +2037,7 @@ ApiWrap *MainWidget::api() {
} }
void MainWidget::updateReplyTo() { void MainWidget::updateReplyTo() {
history.updateReplyTo(true); history.updateReplyEditTexts(true);
} }
void MainWidget::updateBotKeyboard(History *h) { void MainWidget::updateBotKeyboard(History *h) {

View File

@ -1217,3 +1217,7 @@ struct MessageCursor {
} }
int position, anchor, scroll; int position, anchor, scroll;
}; };
inline bool operator==(const MessageCursor &a, const MessageCursor &b) {
return (a.position == b.position) && (a.anchor == b.anchor) && (a.scroll == b.scroll);
}

View File

@ -35,6 +35,8 @@ uint64 _SharedMemoryLocation[4] = { 0x00, 0x01, 0x02, 0x03 };
// Base types compile-time check // Base types compile-time check
NilPointer Nil;
namespace { namespace {
template <typename T, int N> template <typename T, int N>
class _TypeSizeCheckerHelper { class _TypeSizeCheckerHelper {

View File

@ -36,6 +36,22 @@ T *exchange(T *&ptr) {
struct NullType { struct NullType {
}; };
class NilPointer {
public:
template <typename T>
operator T*() const {
return 0;
}
template <typename C, typename T>
operator T C::*() const {
return 0;
}
private:
void operator&() const;
};
extern NilPointer Nil;
template <typename T> template <typename T>
class OrderedSet : public QMap<T, NullType> { class OrderedSet : public QMap<T, NullType> {
public: public:

View File

@ -34,8 +34,8 @@ IDI_ICON1 ICON "SourceFiles\\art\\icon256.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,9,26,0 FILEVERSION 0,9,26,1
PRODUCTVERSION 0,9,26,0 PRODUCTVERSION 0,9,26,1
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -51,10 +51,10 @@ BEGIN
BLOCK "040904b0" BLOCK "040904b0"
BEGIN BEGIN
VALUE "CompanyName", "Telegram Messenger LLP" VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileVersion", "0.9.26.0" VALUE "FileVersion", "0.9.26.1"
VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop" VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.9.26.0" VALUE "ProductVersion", "0.9.26.1"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -1739,7 +1739,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = YES; COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 0.9.25; CURRENT_PROJECT_VERSION = 0.9.26;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_OPTIMIZATION_LEVEL = fast; GCC_OPTIMIZATION_LEVEL = fast;
GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h; GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
@ -1768,10 +1768,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = ""; CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.9.25; CURRENT_PROJECT_VERSION = 0.9.26;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DYLIB_COMPATIBILITY_VERSION = 0.9; DYLIB_COMPATIBILITY_VERSION = 0.9;
DYLIB_CURRENT_VERSION = 0.9.25; DYLIB_CURRENT_VERSION = 0.9.26;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = ""; FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
@ -1909,10 +1909,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = ""; CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.9.25; CURRENT_PROJECT_VERSION = 0.9.26;
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 0.9; DYLIB_COMPATIBILITY_VERSION = 0.9;
DYLIB_CURRENT_VERSION = 0.9.25; DYLIB_CURRENT_VERSION = 0.9.26;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = ""; FRAMEWORK_SEARCH_PATHS = "";

View File

@ -3,4 +3,4 @@ AppVersionStrMajor 0.9
AppVersionStrSmall 0.9.26 AppVersionStrSmall 0.9.26
AppVersionStr 0.9.26 AppVersionStr 0.9.26
DevChannel 0 DevChannel 0
BetaVersion 0 9019002 BetaVersion 9026001