diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index ddb94810ef..05c41a793e 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -162,6 +162,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_pinned_unpin" = "Unpin"; "lng_pinned_notify" = "Notify all members"; +"lng_edit_media" = "Edit media"; + "lng_intro_about" = "Welcome to the official Telegram Desktop app.\nIt's fast and secure."; "lng_start_msgs" = "START MESSAGING"; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 90a923d536..1148f103c1 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -4467,6 +4467,27 @@ void ApiWrap::sendVoiceMessage( caption)); } +void ApiWrap::editMedia( + Storage::PreparedList &&list, + SendMediaType type, + TextWithTags &&caption, + const SendOptions &options) { + LOG(("EDIT MEDIA WITH TEXT %1").arg(caption.text)); + const auto to = fileLoadTaskOptions(options); + auto tasks = std::vector>(); + tasks.reserve(list.files.size()); + for (auto &file : list.files) { + tasks.push_back(std::make_unique( + file.path, + file.content, + std::move(file.information), + type, + to, + caption)); + } + _fileLoader->addTasks(std::move(tasks)); +} + void ApiWrap::sendFiles( Storage::PreparedList &&list, SendMediaType type, @@ -4589,6 +4610,96 @@ void ApiWrap::sendUploadedDocument( } } +void ApiWrap::editUploadedPhoto( + FullMsgId localId, + const MTPInputFile &file, + bool silent) { + if (const auto item = App::histItemById(localId)) { + const auto media = MTP_inputMediaUploadedPhoto( + MTP_flags(0), + file, + MTPVector(), + MTP_int(0)); + + auto flags2 = MTPmessages_EditMessage::Flag::f_message | 0; + flags2 |= MTPmessages_EditMessage::Flag::f_no_webpage; + flags2 |= MTPmessages_EditMessage::Flag::f_entities; + flags2 |= MTPmessages_EditMessage::Flag::f_media; + + auto sentEntities = TextUtilities::EntitiesToMTP( + item->originalText().entities, + TextUtilities::ConvertOption::SkipLocal); + + request(MTPmessages_EditMessage( + MTP_flags(flags2), + item->history()->peer->input, + MTP_int(item->id), + MTP_string(item->originalText().text), + media, + MTPReplyMarkup(), + sentEntities + )).done([=](const MTPUpdates &result) { LOG(("APPLY.")); applyUpdates(result); + }).fail([=](const RPCError &error) { LOG(("FAIL.")); + }).send(); + } +} + +void ApiWrap::editUploadedDocument( + FullMsgId localId, + const MTPInputFile &file, + const std::optional &thumb, + bool silent) { + if (const auto item = App::histItemById(localId)) { + QString filename = "file"; + if (const auto document = item->media()->document()) { + filename = document->filename(); + + const auto filenameAttribute = MTP_documentAttributeFilename( + MTP_string(filename)); + auto attributes = QVector(1, filenameAttribute); + + const auto groupId = item->groupId(); + const auto flags = MTPDinputMediaUploadedDocument::Flags(0) + | (thumb + ? MTPDinputMediaUploadedDocument::Flag::f_thumb + : MTPDinputMediaUploadedDocument::Flag(0)) + | (groupId + ? MTPDinputMediaUploadedDocument::Flag::f_nosound_video + : MTPDinputMediaUploadedDocument::Flag(0)); + const auto media = MTP_inputMediaUploadedDocument( + MTP_flags(flags), + file, + thumb ? *thumb : MTPInputFile(), + MTP_string(document->mimeString()), + ComposeSendingDocumentAttributes(document), + MTPVector(), + MTP_int(0)); + + auto flags2 = MTPmessages_EditMessage::Flag::f_message | 0; + flags2 |= MTPmessages_EditMessage::Flag::f_no_webpage; + flags2 |= MTPmessages_EditMessage::Flag::f_entities; + flags2 |= MTPmessages_EditMessage::Flag::f_media; + + auto sentEntities = TextUtilities::EntitiesToMTP( + item->originalText().entities, + TextUtilities::ConvertOption::SkipLocal); + + + request(MTPmessages_EditMessage( + MTP_flags(flags2), + item->history()->peer->input, + MTP_int(item->id), + MTP_string(item->originalText().text), + media, + MTPReplyMarkup(), + sentEntities + )).done([=](const MTPUpdates &result) { LOG(("APPLY.")); applyUpdates(result); + }).fail([=](const RPCError &error) { LOG(("FAIL.")); + }).send(); + } + } +} + void ApiWrap::cancelLocalItem(not_null item) { Expects(!IsServerMsgId(item->id)); diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 0c00072d88..46cee107b0 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -328,6 +328,12 @@ public: SendMediaType type, const SendOptions &options); + void editMedia( + Storage::PreparedList &&list, + SendMediaType type, + TextWithTags &&caption, + const SendOptions &options); + void sendUploadedPhoto( FullMsgId localId, const MTPInputFile &file, @@ -337,6 +343,16 @@ public: const MTPInputFile &file, const std::optional &thumb, bool silent); + void editUploadedDocument( + FullMsgId localId, + const MTPInputFile &file, + const std::optional &thumb, + bool silent); + void editUploadedPhoto( + FullMsgId localId, + const MTPInputFile &file, + bool silent); + void cancelLocalItem(not_null item); struct MessageToSend { diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp index 5c4e147afc..02c55f155a 100644 --- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp @@ -32,6 +32,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_boxes.h" #include "styles/style_chat_helpers.h" +#include "storage/storage_media_prepare.h" + +#include "core/application.h" +#include "mainwidget.h" + +#include "core/file_utilities.h" + EditCaptionBox::EditCaptionBox( QWidget*, not_null controller, @@ -308,6 +315,28 @@ void EditCaptionBox::clipCallback(Media::Clip::Notification notification) { void EditCaptionBox::prepare() { addButton(langFactory(lng_settings_save), [this] { save(); }); + addButton(langFactory(lng_edit_media), [this] { + const auto callback = [=](const FileDialog::OpenResult &result) { + if (result.paths.isEmpty() && result.remoteContent.isEmpty()) { + return; + } + + if (!result.paths.isEmpty()) { + const auto filePath = result.paths.front(); + LOG(("FILE PATH: %1").arg(filePath)); + _newMediaPath = filePath; + } + }; + + auto filters = QStringList(qsl("Any File (*.*)")); + filters.push_back(FileDialog::AllFilesFilter()); + + FileDialog::GetOpenPath( + this, + lang(lng_choose_image), + filters.join(qsl(";;")), + crl::guard(this, callback)); + }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); updateBoxSize(); @@ -522,6 +551,33 @@ void EditCaptionBox::save() { if (!sentEntities.v.isEmpty()) { flags |= MTPmessages_EditMessage::Flag::f_entities; } + + if (!_newMediaPath.isEmpty()) { + App::main()->setEditMedia(item->fullId()); + const auto textWithTags = _field->getTextWithAppliedMarkdown(); + auto sending = TextWithEntities{ + textWithTags.text, + ConvertTextTagsToEntities(textWithTags.tags) + }; + item->setText(sending); + + static const auto extensions = { + qstr(".jpg"), + qstr(".png"), + }; + const auto isPhoto = std::find_if(std::begin(extensions), std::end(extensions), [=](auto &extension) { + return _newMediaPath.endsWith(extension, Qt::CaseInsensitive); + }) != std::end(extensions); + + Auth().api().editMedia( + Storage::PrepareMediaList(QStringList(_newMediaPath), st::sendMediaPreviewSize), + isPhoto ? SendMediaType::Photo : SendMediaType::File, + _field->getTextWithAppliedMarkdown(), + ApiWrap::SendOptions(item->history())); + closeBox(); + return; + } + _saveRequestId = MTP::send( MTPmessages_EditMessage( MTP_flags(flags), diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.h b/Telegram/SourceFiles/boxes/edit_caption_box.h index f33feab53d..a4cfefae5f 100644 --- a/Telegram/SourceFiles/boxes/edit_caption_box.h +++ b/Telegram/SourceFiles/boxes/edit_caption_box.h @@ -94,6 +94,8 @@ private: bool _previewCancelled = false; mtpRequestId _saveRequestId = 0; + QString _newMediaPath; + QString _error; }; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 1026fb568b..15773e2a0f 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -3054,6 +3054,7 @@ void HistoryWidget::chooseAttach() { uploadFile(result.remoteContent, SendMediaType::File); } } else { + LOG((result.paths[0])); auto list = Storage::PrepareMediaList( result.paths, st::sendMediaPreviewSize); @@ -4172,14 +4173,16 @@ void HistoryWidget::uploadFile( Auth().api().sendFile(fileContent, type, options); } -void HistoryWidget::subscribeToUploader() { +void HistoryWidget::subscribeToUploader(bool edit) { if (_uploaderSubscriptions) { return; } using namespace Storage; Auth().uploader().photoReady( ) | rpl::start_with_next([=](const UploadedPhoto &data) { - photoUploaded(data.fullId, data.silent, data.file); + edit + ? photoEdited(data.fullId, data.silent, data.file) + : photoUploaded(data.fullId, data.silent, data.file); }, _uploaderSubscriptions); Auth().uploader().photoProgress( ) | rpl::start_with_next([=](const FullMsgId &fullId) { @@ -4191,7 +4194,9 @@ void HistoryWidget::subscribeToUploader() { }, _uploaderSubscriptions); Auth().uploader().documentReady( ) | rpl::start_with_next([=](const UploadedDocument &data) { - documentUploaded(data.fullId, data.silent, data.file); + edit + ? documentEdited(data.fullId, data.silent, data.file) + : documentUploaded(data.fullId, data.silent, data.file); }, _uploaderSubscriptions); Auth().uploader().thumbDocumentReady( ) | rpl::start_with_next([=](const UploadedThumbDocument &data) { @@ -4212,13 +4217,15 @@ void HistoryWidget::subscribeToUploader() { } void HistoryWidget::sendFileConfirmed( - const std::shared_ptr &file) { + const std::shared_ptr &file, + const std::optional &oldId) { + const auto isEditing = oldId.has_value(); const auto channelId = peerToChannel(file->to.peer); const auto lastKeyboardUsed = lastForceReplyReplied(FullMsgId( channelId, file->to.replyTo)); - const auto newId = FullMsgId(channelId, clientMsgId()); + const auto newId = oldId.value_or(FullMsgId(channelId, clientMsgId())); const auto groupId = file->album ? file->album->groupId : uint64(0); if (file->album) { const auto proj = [](const SendingAlbum::Item &item) { @@ -4230,7 +4237,7 @@ void HistoryWidget::sendFileConfirmed( it->msgId = newId; } - subscribeToUploader(); + subscribeToUploader(isEditing); Auth().uploader().upload(newId, file); @@ -4363,6 +4370,10 @@ void HistoryWidget::sendFileConfirmed( Unexpected("Type in sendFilesConfirmed."); } + if (isEditing) { + return; + } + Auth().data().sendHistoryChangeNotifications(); if (_peer && file->to.peer == _peer->id) { App::main()->historyToDown(_history); @@ -4384,6 +4395,22 @@ void HistoryWidget::documentUploaded( Auth().api().sendUploadedDocument(newId, file, std::nullopt, silent); } +void HistoryWidget::documentEdited( + const FullMsgId &newId, + bool silent, + const MTPInputFile &file) { + LOG(("DOCUMENT EDITED %1").arg(newId.msg)); + Auth().api().editUploadedDocument(newId, file, std::nullopt, silent); +} + +void HistoryWidget::photoEdited( + const FullMsgId &newId, + bool silent, + const MTPInputFile &file) { + LOG(("PHOTO EDITED %1").arg(newId.msg)); + Auth().api().editUploadedPhoto(newId, file, silent); +} + void HistoryWidget::thumbDocumentUploaded( const FullMsgId &newId, bool silent, @@ -4412,6 +4439,8 @@ void HistoryWidget::documentProgress(const FullMsgId &newId) { const auto progress = (document && document->uploading()) ? document->uploadingData->offset : 0; + + LOG(("ITEM EXISTS %1 TYPE: %2 PROGRESS: %3").arg(newId.msg).arg(sendAction == SendAction::Type::UploadFile).arg(progress)); updateSendAction( item->history(), sendAction, diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 91cff86411..d81990dce1 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -160,7 +160,8 @@ public: bool confirmSendingFiles(const QStringList &files); bool confirmSendingFiles(not_null data); - void sendFileConfirmed(const std::shared_ptr &file); + void sendFileConfirmed(const std::shared_ptr &file, + const std::optional &oldId = std::nullopt); void updateControlsVisibility(); void updateControlsGeometry(); @@ -441,7 +442,7 @@ private: MsgId replyTo, std::shared_ptr album = nullptr); - void subscribeToUploader(); + void subscribeToUploader(bool edit = false); void photoUploaded( const FullMsgId &msgId, @@ -461,6 +462,16 @@ private: void documentProgress(const FullMsgId &msgId); void documentFailed(const FullMsgId &msgId); + void documentEdited( + const FullMsgId &msgId, + bool silent, + const MTPInputFile &file); + + void photoEdited( + const FullMsgId &msgId, + bool silent, + const MTPInputFile &file); + void itemRemoved(not_null item); // Updates position of controls around the message field, diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 28d30c24cc..8c21755b7f 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -842,11 +842,11 @@ void MainWidget::cancelUploadLayer(not_null item) { Ui::hideLayer(); if (const auto item = App::histItemById(itemId)) { const auto history = item->history(); - item->destroy(); + //item->destroy(); history->requestChatListMessage(); session().data().sendHistoryChangeNotifications(); } - session().uploader().unpause(); + //session().uploader().unpause(); }; const auto continueUpload = [=] { session().uploader().unpause(); @@ -1315,6 +1315,13 @@ void MainWidget::onSendFileConfirm( _history->sendFileConfirmed(file); } +void MainWidget::onEditMedia( + const std::shared_ptr &file, + const FullMsgId &oldId) { + LOG(("ON EDIT MEDIA")); + _history->sendFileConfirmed(file, oldId); +} + bool MainWidget::onSendSticker(DocumentData *document) { return _history->sendExistingDocument(document); } @@ -3706,6 +3713,7 @@ void MainWidget::updateReceived(const mtpPrime *from, const mtpPrime *end) { void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { switch (updates.type()) { case mtpc_updates: { + LOG(("TYPE 1")); auto &d = updates.c_updates(); if (d.vseq.v) { if (d.vseq.v <= updSeq) { @@ -3726,6 +3734,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { } break; case mtpc_updatesCombined: { + LOG(("TYPE 2")); auto &d = updates.c_updatesCombined(); if (d.vseq_start.v) { if (d.vseq_start.v <= updSeq) { @@ -3746,6 +3755,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { } break; case mtpc_updateShort: { + LOG(("TYPE 3")); auto &d = updates.c_updateShort(); feedUpdate(d.vupdate); @@ -3753,6 +3763,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { } break; case mtpc_updateShortMessage: { + LOG(("TYPE 4")); auto &d = updates.c_updateShortMessage(); if (!session().data().userLoaded(d.vuser_id.v) || (d.has_via_bot_id() && !session().data().userLoaded(d.vvia_bot_id.v)) @@ -3768,6 +3779,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { } break; case mtpc_updateShortChatMessage: { + LOG(("TYPE 5")); auto &d = updates.c_updateShortChatMessage(); const auto noFrom = !session().data().userLoaded(d.vfrom_id.v); const auto chat = session().data().chatLoaded(d.vchat_id.v); @@ -3789,6 +3801,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { } break; case mtpc_updateShortSentMessage: { + LOG(("TYPE 6")); auto &d = updates.c_updateShortSentMessage(); if (!IsServerMsgId(d.vid.v)) { LOG(("API Error: Bad msgId got from server: %1").arg(d.vid.v)); @@ -3828,6 +3841,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { } break; case mtpc_updatesTooLong: { + LOG(("TYPE 7")); MTP_LOG(0, ("getDifference { good - updatesTooLong received }%1").arg(cTestMode() ? " TESTMODE" : "")); return getDifference(); } break; diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 6d00a8cfb6..56779469b0 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -111,6 +111,13 @@ public: void start(); + void setEditMedia(FullMsgId flag) { + _editMedia = flag; + } + FullMsgId getEditMedia() const { + return _editMedia; + } + void openPeerByName( const QString &name, MsgId msgId = ShowAtUnreadMsgId, @@ -159,6 +166,8 @@ public: void checkMainSectionToLayer(); void onSendFileConfirm(const std::shared_ptr &file); + void onEditMedia(const std::shared_ptr &file, + const FullMsgId &oldId); bool onSendSticker(DocumentData *sticker); void destroyData(); @@ -544,4 +553,6 @@ private: bool _firstColumnResizing = false; int _firstColumnResizingShift = 0; + FullMsgId _editMedia; + }; diff --git a/Telegram/SourceFiles/storage/localimageloader.cpp b/Telegram/SourceFiles/storage/localimageloader.cpp index 5fcbad7813..3179dfec88 100644 --- a/Telegram/SourceFiles/storage/localimageloader.cpp +++ b/Telegram/SourceFiles/storage/localimageloader.cpp @@ -975,6 +975,9 @@ void FileLoadTask::finish() { lng_send_image_too_large(lt_name, _filepath)), LayerOption::KeepOther); removeFromAlbum(); + } else if (App::main()->getEditMedia()) { + LOG(("FINISH UPLOAD EDIT")); + App::main()->onEditMedia(_result, App::main()->getEditMedia()); } else if (App::main()) { App::main()->onSendFileConfirm(_result); }