void HistoryMessage::setText(const TextWithEntities &textWithEntities) { for_const (auto &entity, textWithEntities.entities) { auto type = entity.type(); if (type == EntityInTextUrl || type == EntityInTextCustomUrl || type == EntityInTextEmail) { _flags |= MTPDmessage_ClientFlag::f_has_text_links; break; } } if (_media && _media->consumeMessageText(textWithEntities)) { setEmptyText(); } else { _text.setMarkedText( st::messageTextStyle, textWithEntities, Ui::ItemTextOptions(this)); if (!textWithEntities.text.isEmpty() && _text.isEmpty()) { // If server has allowed some text that we've trim-ed entirely, // just replace it with something so that UI won't look buggy. _text.setMarkedText( st::messageTextStyle, { QString::fromUtf8("\xF0\x9F\x98\x94"), EntitiesInText() }, Ui::ItemTextOptions(this)); } _textWidth = -1; _textHeight = 0; } }
void InviteLinkWidget::refreshLink() { _link.destroy(); TextWithEntities linkData = { getInviteLink(), EntitiesInText() }; if (linkData.text.isEmpty()) { _link.destroy(); } else { _link = new FlatLabel(this, QString(), FlatLabel::InitType::Simple, st::profileInviteLinkText); _link->show(); linkData.entities.push_back(EntityInText(EntityInTextUrl, 0, linkData.text.size())); _link->setMarkedText(linkData); _link->setSelectable(true); _link->setContextCopyText(QString()); _link->setClickHandlerHook([this](const ClickHandlerPtr &handler, Qt::MouseButton button) { auto link = getInviteLink(); if (link.isEmpty()) { return true; } QApplication::clipboard()->setText(link); Ui::showLayer(new InformBox(lang(lng_group_invite_copied))); return false; }); } }
void HistoryMessage::applyEdition(const MTPDmessage &message) { int keyboardTop = -1; //if (!pendingResize()) {// #TODO edit bot message // if (auto keyboard = inlineReplyKeyboard()) { // int h = st::msgBotKbButton.margin + keyboard->naturalHeight(); // keyboardTop = _height - h + st::msgBotKbButton.margin - marginBottom(); // } //} if (message.has_edit_date()) { _flags |= MTPDmessage::Flag::f_edit_date; if (!Has<HistoryMessageEdited>()) { AddComponents(HistoryMessageEdited::Bit()); } auto edited = Get<HistoryMessageEdited>(); edited->date = message.vedit_date.v; } TextWithEntities textWithEntities = { qs(message.vmessage), EntitiesInText() }; if (message.has_entities()) { textWithEntities.entities = TextUtilities::EntitiesFromMTP(message.ventities.v); } setReplyMarkup(message.has_reply_markup() ? (&message.vreply_markup) : nullptr); refreshMedia(message.has_media() ? (&message.vmedia) : nullptr); setViewsCount(message.has_views() ? message.vviews.v : -1); setText(textWithEntities); finishEdition(keyboardTop); }
void applyPeerCloudDraft(PeerId peerId, const MTPDdraftMessage &draft) { const auto history = App::history(peerId); const auto textWithTags = TextWithTags { qs(draft.vmessage), ConvertEntitiesToTextTags( draft.has_entities() ? TextUtilities::EntitiesFromMTP(draft.ventities.v) : EntitiesInText()) }; auto replyTo = draft.has_reply_to_msg_id() ? draft.vreply_to_msg_id.v : MsgId(0); if (history->skipCloudDraft(textWithTags.text, replyTo, draft.vdate.v)) { return; } auto cloudDraft = std::make_unique<Draft>( textWithTags, replyTo, MessageCursor(QFIXED_MAX, QFIXED_MAX, QFIXED_MAX), draft.is_no_webpage()); cloudDraft->date = draft.vdate.v; history->setCloudDraft(std::move(cloudDraft)); history->createLocalDraftFromCloud(); if (Auth().supportMode()) { history->updateChatListEntry(); Auth().supportHelper().cloudDraftChanged(history); } else { history->updateChatListSortPosition(); } if (const auto main = App::main()) { main->applyCloudDraft(history); } }
void HistoryMessage::setEmptyText() { _text.setMarkedText( st::messageTextStyle, { QString(), EntitiesInText() }, Ui::ItemTextOptions(this)); _textWidth = -1; _textHeight = 0; }
void HistoryInvoice::fillFromData(not_null<Data::Invoice*> invoice) { if (invoice->photo) { _attach = std::make_unique<HistoryPhoto>( _parent, _parent->data(), invoice->photo); } else { _attach = nullptr; } auto labelText = [&] { if (invoice->receiptMsgId) { if (invoice->isTest) { return lang(lng_payments_receipt_label_test); } return lang(lng_payments_receipt_label); } else if (invoice->isTest) { return lang(lng_payments_invoice_label_test); } return lang(lng_payments_invoice_label); }; auto statusText = TextWithEntities { FillAmountAndCurrency(invoice->amount, invoice->currency), EntitiesInText() }; statusText.entities.push_back({ EntityType::Bold, 0, statusText.text.size() }); statusText.text += ' ' + labelText().toUpper(); _status.setMarkedText( st::defaultTextStyle, statusText, Ui::ItemTextOptions(_parent->data())); _receiptMsgId = invoice->receiptMsgId; // init strings if (!invoice->description.isEmpty()) { auto marked = TextWithEntities { invoice->description }; auto parseFlags = TextParseLinks | TextParseMultiline | TextParseRichText; TextUtilities::ParseEntities(marked, parseFlags); _description.setMarkedText( st::webPageDescriptionStyle, marked, Ui::WebpageTextDescriptionOptions()); } if (!invoice->title.isEmpty()) { _title.setText( st::webPageTitleStyle, invoice->title, Ui::WebpageTextTitleOptions()); } }
HistoryMessage::HistoryMessage( not_null<History*> history, const MTPDmessage &data) : HistoryItem( history, data.vid.v, data.vflags.v, data.vdate.v, data.has_from_id() ? data.vfrom_id.v : UserId(0)) { CreateConfig config; if (data.has_fwd_from() && data.vfwd_from.type() == mtpc_messageFwdHeader) { auto &f = data.vfwd_from.c_messageFwdHeader(); config.originalDate = f.vdate.v; if (f.has_from_id() || f.has_channel_id()) { config.senderOriginal = f.has_channel_id() ? peerFromChannel(f.vchannel_id) : peerFromUser(f.vfrom_id); if (f.has_channel_post()) config.originalId = f.vchannel_post.v; if (f.has_post_author()) config.authorOriginal = qs(f.vpost_author); if (f.has_saved_from_peer() && f.has_saved_from_msg_id()) { config.savedFromPeer = peerFromMTP(f.vsaved_from_peer); config.savedFromMsgId = f.vsaved_from_msg_id.v; } } } if (data.has_reply_to_msg_id()) config.replyTo = data.vreply_to_msg_id.v; if (data.has_via_bot_id()) config.viaBotId = data.vvia_bot_id.v; if (data.has_views()) config.viewsCount = data.vviews.v; if (data.has_reply_markup()) config.mtpMarkup = &data.vreply_markup; if (data.has_edit_date()) config.editDate = data.vedit_date.v; if (data.has_post_author()) config.author = qs(data.vpost_author); createComponents(config); if (data.has_media()) { setMedia(data.vmedia); } auto text = TextUtilities::Clean(qs(data.vmessage)); auto entities = data.has_entities() ? TextUtilities::EntitiesFromMTP(data.ventities.v) : EntitiesInText(); setText({ text, entities }); if (data.has_grouped_id()) { setGroupId(MessageGroupId::FromRaw(data.vgrouped_id.v)); } }
TextWithEntities HistoryMessage::clipboardText() const { if (emptyText()) { return { QString(), EntitiesInText() }; } return _text.originalTextWithEntities(AllTextSelection, ExpandLinksAll); }
TextWithEntities HistoryMessage::originalText() const { if (emptyText()) { return { QString(), EntitiesInText() }; } return _text.originalTextWithEntities(); }
std::unique_ptr<Result> Result::create(uint64 queryId, const MTPBotInlineResult &mtpData) { using StringToTypeMap = QMap<QString, Result::Type>; static StaticNeverFreedPointer<StringToTypeMap> stringToTypeMap{ ([]() -> StringToTypeMap* { auto result = std::make_unique<StringToTypeMap>(); result->insert(qsl("photo"), Result::Type::Photo); result->insert(qsl("video"), Result::Type::Video); result->insert(qsl("audio"), Result::Type::Audio); result->insert(qsl("voice"), Result::Type::Audio); result->insert(qsl("sticker"), Result::Type::Sticker); result->insert(qsl("file"), Result::Type::File); result->insert(qsl("gif"), Result::Type::Gif); result->insert(qsl("article"), Result::Type::Article); result->insert(qsl("contact"), Result::Type::Contact); result->insert(qsl("venue"), Result::Type::Venue); result->insert(qsl("geo"), Result::Type::Geo); result->insert(qsl("game"), Result::Type::Game); return result.release(); })() }; auto getInlineResultType = [](const MTPBotInlineResult &inlineResult) -> Type { QString type; switch (inlineResult.type()) { case mtpc_botInlineResult: type = qs(inlineResult.c_botInlineResult().vtype); break; case mtpc_botInlineMediaResult: type = qs(inlineResult.c_botInlineMediaResult().vtype); break; } return stringToTypeMap->value(type, Type::Unknown); }; Type type = getInlineResultType(mtpData); if (type == Type::Unknown) { return nullptr; } auto result = std::make_unique<Result>(Creator{ queryId, type }); const MTPBotInlineMessage *message = nullptr; switch (mtpData.type()) { case mtpc_botInlineResult: { const auto &r = mtpData.c_botInlineResult(); result->_id = qs(r.vid); if (r.has_title()) result->_title = qs(r.vtitle); if (r.has_description()) result->_description = qs(r.vdescription); if (r.has_url()) result->_url = qs(r.vurl); if (r.has_thumb()) { result->_thumb = ImagePtr(r.vthumb, result->thumbBox()); } if (r.has_content()) { result->_content_url = GetContentUrl(r.vcontent); if (result->_type == Type::Photo) { result->_photo = Auth().data().photoFromWeb( r.vcontent, result->_thumb); } else { result->_document = Auth().data().documentFromWeb( result->adjustAttributes(r.vcontent), result->_thumb); } } message = &r.vsend_message; } break; case mtpc_botInlineMediaResult: { const auto &r = mtpData.c_botInlineMediaResult(); result->_id = qs(r.vid); if (r.has_title()) result->_title = qs(r.vtitle); if (r.has_description()) result->_description = qs(r.vdescription); if (r.has_photo()) { result->_photo = Auth().data().photo(r.vphoto); } if (r.has_document()) { result->_document = Auth().data().document(r.vdocument); } message = &r.vsend_message; } break; } auto badAttachment = (result->_photo && result->_photo->full->isNull()) || (result->_document && !result->_document->isValid()); if (!message) { return nullptr; } // Ensure required media fields for layouts. if (result->_type == Type::Photo) { if (!result->_photo) { return nullptr; } } else if (result->_type == Type::Audio || result->_type == Type::File || result->_type == Type::Video || result->_type == Type::Sticker || result->_type == Type::Gif) { if (!result->_document) { return nullptr; } } switch (message->type()) { case mtpc_botInlineMessageMediaAuto: { auto &r = message->c_botInlineMessageMediaAuto(); auto entities = r.has_entities() ? TextUtilities::EntitiesFromMTP(r.ventities.v) : EntitiesInText(); if (result->_type == Type::Photo) { if (!result->_photo) { return nullptr; } result->sendData = std::make_unique<internal::SendPhoto>(result->_photo, qs(r.vmessage), entities); } else if (result->_type == Type::Game) { result->createGame(); result->sendData = std::make_unique<internal::SendGame>(result->_game); } else { if (!result->_document) { return nullptr; } result->sendData = std::make_unique<internal::SendFile>(result->_document, qs(r.vmessage), entities); } if (r.has_reply_markup()) { result->_mtpKeyboard = std::make_unique<MTPReplyMarkup>(r.vreply_markup); } } break; case mtpc_botInlineMessageText: { auto &r = message->c_botInlineMessageText(); auto entities = r.has_entities() ? TextUtilities::EntitiesFromMTP(r.ventities.v) : EntitiesInText(); result->sendData = std::make_unique<internal::SendText>(qs(r.vmessage), entities, r.is_no_webpage()); if (result->_type == Type::Photo) { if (!result->_photo) { return nullptr; } } else if (result->_type == Type::Audio || result->_type == Type::File || result->_type == Type::Video || result->_type == Type::Sticker || result->_type == Type::Gif) { if (!result->_document) { return nullptr; } } if (r.has_reply_markup()) { result->_mtpKeyboard = std::make_unique<MTPReplyMarkup>(r.vreply_markup); } } break; case mtpc_botInlineMessageMediaGeo: { // #TODO layer 72 save period and send live location?.. auto &r = message->c_botInlineMessageMediaGeo(); if (r.vgeo.type() == mtpc_geoPoint) { result->sendData = std::make_unique<internal::SendGeo>(r.vgeo.c_geoPoint()); } else { badAttachment = true; } if (r.has_reply_markup()) { result->_mtpKeyboard = std::make_unique<MTPReplyMarkup>(r.vreply_markup); } } break; case mtpc_botInlineMessageMediaVenue: { auto &r = message->c_botInlineMessageMediaVenue(); if (r.vgeo.type() == mtpc_geoPoint) { result->sendData = std::make_unique<internal::SendVenue>(r.vgeo.c_geoPoint(), qs(r.vvenue_id), qs(r.vprovider), qs(r.vtitle), qs(r.vaddress)); } else { badAttachment = true; } if (r.has_reply_markup()) { result->_mtpKeyboard = std::make_unique<MTPReplyMarkup>(r.vreply_markup); } } break; case mtpc_botInlineMessageMediaContact: { auto &r = message->c_botInlineMessageMediaContact(); result->sendData = std::make_unique<internal::SendContact>(qs(r.vfirst_name), qs(r.vlast_name), qs(r.vphone_number)); if (r.has_reply_markup()) { result->_mtpKeyboard = std::make_unique<MTPReplyMarkup>(r.vreply_markup); } } break; default: { badAttachment = true; } break; } if (badAttachment || !result->sendData || !result->sendData->isValid()) { return nullptr; } LocationCoords location; if (result->getLocationCoords(&location)) { int32 w = st::inlineThumbSize, h = st::inlineThumbSize; int32 zoom = 13, scale = 1; if (cScale() == dbisTwo || cRetina()) { scale = 2; w /= 2; h /= 2; } auto coords = location.latAsString() + ',' + location.lonAsString(); QString url = qsl("https://maps.googleapis.com/maps/api/staticmap?center=") + coords + qsl("&zoom=%1&size=%2x%3&maptype=roadmap&scale=%4&markers=color:red|size:big|").arg(zoom).arg(w).arg(h).arg(scale) + coords + qsl("&sensor=false"); result->_locationThumb = ImagePtr(url); } return result; }
std_::unique_ptr<Result> Result::create(uint64 queryId, const MTPBotInlineResult &mtpData) { using StringToTypeMap = QMap<QString, Result::Type>; static StaticNeverFreedPointer<StringToTypeMap> stringToTypeMap{ ([]() -> StringToTypeMap* { auto result = std_::make_unique<StringToTypeMap>(); result->insert(qsl("photo"), Result::Type::Photo); result->insert(qsl("video"), Result::Type::Video); result->insert(qsl("audio"), Result::Type::Audio); result->insert(qsl("voice"), Result::Type::Audio); result->insert(qsl("sticker"), Result::Type::Sticker); result->insert(qsl("file"), Result::Type::File); result->insert(qsl("gif"), Result::Type::Gif); result->insert(qsl("article"), Result::Type::Article); result->insert(qsl("contact"), Result::Type::Contact); result->insert(qsl("venue"), Result::Type::Venue); result->insert(qsl("geo"), Result::Type::Geo); result->insert(qsl("game"), Result::Type::Game); return result.release(); })() }; auto getInlineResultType = [](const MTPBotInlineResult &inlineResult) -> Type { QString type; switch (inlineResult.type()) { case mtpc_botInlineResult: type = qs(inlineResult.c_botInlineResult().vtype); break; case mtpc_botInlineMediaResult: type = qs(inlineResult.c_botInlineMediaResult().vtype); break; } return stringToTypeMap->value(type, Type::Unknown); }; Type type = getInlineResultType(mtpData); if (type == Type::Unknown) { return std_::unique_ptr<Result>(); } auto result = std_::make_unique<Result>(Creator{ queryId, type }); const MTPBotInlineMessage *message = nullptr; switch (mtpData.type()) { case mtpc_botInlineResult: { const auto &r(mtpData.c_botInlineResult()); result->_id = qs(r.vid); if (r.has_title()) result->_title = qs(r.vtitle); if (r.has_description()) result->_description = qs(r.vdescription); if (r.has_url()) result->_url = qs(r.vurl); if (r.has_thumb_url()) result->_thumb_url = qs(r.vthumb_url); if (r.has_content_type()) result->_content_type = qs(r.vcontent_type); if (r.has_content_url()) result->_content_url = qs(r.vcontent_url); if (r.has_w()) result->_width = r.vw.v; if (r.has_h()) result->_height = r.vh.v; if (r.has_duration()) result->_duration = r.vduration.v; if (!result->_thumb_url.startsWith(qstr("http://"), Qt::CaseInsensitive) && !result->_thumb_url.startsWith(qstr("https://"), Qt::CaseInsensitive)) { result->_thumb_url = QString(); } message = &r.vsend_message; } break; case mtpc_botInlineMediaResult: { const auto &r(mtpData.c_botInlineMediaResult()); result->_id = qs(r.vid); if (r.has_title()) result->_title = qs(r.vtitle); if (r.has_description()) result->_description = qs(r.vdescription); if (r.has_photo()) { result->_photo = App::feedPhoto(r.vphoto); } if (r.has_document()) { result->_document = App::feedDocument(r.vdocument); } message = &r.vsend_message; } break; } bool badAttachment = (result->_photo && !result->_photo->access) || (result->_document && !result->_document->isValid()); if (!message) { return std_::unique_ptr<Result>(); } // Ensure required media fields for layouts. if (result->_type == Type::Photo) { if (!result->_photo && result->_content_url.isEmpty()) { return std_::unique_ptr<Result>(); } result->createPhoto(); } else if (result->_type == Type::File || result->_type == Type::Gif || result->_type == Type::Sticker) { if (!result->_document && result->_content_url.isEmpty()) { return std_::unique_ptr<Result>(); } result->createDocument(); } switch (message->type()) { case mtpc_botInlineMessageMediaAuto: { auto &r = message->c_botInlineMessageMediaAuto(); if (result->_type == Type::Photo) { result->createPhoto(); result->sendData.reset(new internal::SendPhoto(result->_photo, qs(r.vcaption))); } else if (result->_type == Type::Game) { result->createGame(); result->sendData.reset(new internal::SendGame(result->_game)); } else { result->createDocument(); result->sendData.reset(new internal::SendFile(result->_document, qs(r.vcaption))); } if (r.has_reply_markup()) { result->_mtpKeyboard = std_::make_unique<MTPReplyMarkup>(r.vreply_markup); } } break; case mtpc_botInlineMessageText: { auto &r = message->c_botInlineMessageText(); EntitiesInText entities = r.has_entities() ? entitiesFromMTP(r.ventities.c_vector().v) : EntitiesInText(); result->sendData.reset(new internal::SendText(qs(r.vmessage), entities, r.is_no_webpage())); if (result->_type == Type::Photo) { result->createPhoto(); } else if (result->_type == Type::Audio || result->_type == Type::File || result->_type == Type::Video || result->_type == Type::Sticker || result->_type == Type::Gif) { result->createDocument(); } if (r.has_reply_markup()) { result->_mtpKeyboard = std_::make_unique<MTPReplyMarkup>(r.vreply_markup); } } break; case mtpc_botInlineMessageMediaGeo: { auto &r = message->c_botInlineMessageMediaGeo(); if (r.vgeo.type() == mtpc_geoPoint) { result->sendData.reset(new internal::SendGeo(r.vgeo.c_geoPoint())); } else { badAttachment = true; } if (r.has_reply_markup()) { result->_mtpKeyboard = std_::make_unique<MTPReplyMarkup>(r.vreply_markup); } } break; case mtpc_botInlineMessageMediaVenue: { auto &r = message->c_botInlineMessageMediaVenue(); if (r.vgeo.type() == mtpc_geoPoint) { result->sendData.reset(new internal::SendVenue(r.vgeo.c_geoPoint(), qs(r.vvenue_id), qs(r.vprovider), qs(r.vtitle), qs(r.vaddress))); } else { badAttachment = true; } if (r.has_reply_markup()) { result->_mtpKeyboard = std_::make_unique<MTPReplyMarkup>(r.vreply_markup); } } break; case mtpc_botInlineMessageMediaContact: { auto &r = message->c_botInlineMessageMediaContact(); result->sendData.reset(new internal::SendContact(qs(r.vfirst_name), qs(r.vlast_name), qs(r.vphone_number))); if (r.has_reply_markup()) { result->_mtpKeyboard = std_::make_unique<MTPReplyMarkup>(r.vreply_markup); } } break; default: { badAttachment = true; } break; } if (badAttachment || !result->sendData || !result->sendData->isValid()) { return std_::unique_ptr<Result>(); } if (result->_thumb->isNull() && !result->_thumb_url.isEmpty()) { result->_thumb = ImagePtr(result->_thumb_url); } LocationCoords location; if (result->getLocationCoords(&location)) { int32 w = st::inlineThumbSize, h = st::inlineThumbSize; int32 zoom = 13, scale = 1; if (cScale() == dbisTwo || cRetina()) { scale = 2; w /= 2; h /= 2; } QString coords = qsl("%1,%2").arg(location.lat).arg(location.lon); QString url = qsl("https://maps.googleapis.com/maps/api/staticmap?center=") + coords + qsl("&zoom=%1&size=%2x%3&maptype=roadmap&scale=%4&markers=color:red|size:big|").arg(zoom).arg(w).arg(h).arg(scale) + coords + qsl("&sensor=false"); result->_locationThumb = ImagePtr(url); } return result; }
TextWithEntities ClickHandler::getExpandedLinkTextWithEntities(ExpandLinksMode mode, int entityOffset, const QStringRef &textPart) const { return { QString(), EntitiesInText() }; }
void applyPeerCloudDraft(PeerId peerId, const MTPDdraftMessage &draft) { auto history = App::history(peerId); auto text = TextWithEntities { qs(draft.vmessage), draft.has_entities() ? TextUtilities::EntitiesFromMTP(draft.ventities.v) : EntitiesInText() }; auto textWithTags = TextWithTags { TextUtilities::ApplyEntities(text), ConvertEntitiesToTextTags(text.entities) }; auto replyTo = draft.has_reply_to_msg_id() ? draft.vreply_to_msg_id.v : MsgId(0); auto cloudDraft = std::make_unique<Draft>(textWithTags, replyTo, MessageCursor(QFIXED_MAX, QFIXED_MAX, QFIXED_MAX), draft.is_no_webpage()); cloudDraft->date = draft.vdate.v; history->setCloudDraft(std::move(cloudDraft)); history->createLocalDraftFromCloud(); history->updateChatListSortPosition(); if (auto main = App::main()) { main->applyCloudDraft(history); } }