Update API scheme on layer 143 + transcribe.

This commit is contained in:
John Preston 2022-05-24 19:38:46 +04:00
parent 3fac522bbc
commit 0b2a5a22ba
14 changed files with 421 additions and 29 deletions

View file

@ -155,6 +155,8 @@ PRIVATE
api/api_text_entities.h
api/api_toggling_media.cpp
api/api_toggling_media.h
api/api_transcribes.cpp
api/api_transcribes.h
api/api_unread_things.cpp
api/api_unread_things.h
api/api_updates.cpp
@ -690,6 +692,8 @@ PRIVATE
history/view/history_view_service_message.h
history/view/history_view_spoiler_click_handler.cpp
history/view/history_view_spoiler_click_handler.h
history/view/history_view_transcribe_button.cpp
history/view/history_view_transcribe_button.h
history/view/history_view_top_bar_widget.cpp
history/view/history_view_top_bar_widget.h
history/view/history_view_view_button.cpp

View file

@ -390,6 +390,7 @@ updateAttachMenuBots#17b7a20b = Update;
updateWebViewResultSent#1592b79d query_id:long = Update;
updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update;
updateSavedRingtones#74d8be99 = Update;
updateTranscribeAudio#88617090 flags:# final:flags.0?true transcription_id:long text:string = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@ -1383,7 +1384,7 @@ inputInvoiceSlug#c326caef slug:string = InputInvoice;
payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice;
messages.transcribedAudio#bfcd7e0a transcription_id:long text:string = messages.TranscribedAudio;
messages.transcribedAudio#93752c52 flags:# pending:flags.0?true transcription_id:long text:string = messages.TranscribedAudio;
---functions---
@ -1790,6 +1791,7 @@ payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?t
payments.getBankCardData#2e79d779 number:string = payments.BankCardData;
payments.exportInvoice#f91b065 invoice_media:InputMedia = payments.ExportedInvoice;
payments.assignAppStoreTransaction#6299a12f transaction_id:string = Updates;
payments.assignPlayMarketTransaction#4faa4aed purchase_token:string = Updates;
stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true animated:flags.1?true videos:flags.4?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector<InputStickerSetItem> software:flags.3?string = messages.StickerSet;
stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet;

View file

@ -0,0 +1,97 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "api/api_transcribes.h"
#include "history/history_item.h"
#include "history/history.h"
#include "main/main_session.h"
#include "data/data_session.h"
#include "data/data_peer.h"
#include "apiwrap.h"
namespace Api {
Transcribes::Transcribes(not_null<ApiWrap*> api)
: _session(&api->session())
, _api(&api->instance()) {
}
void Transcribes::toggle(not_null<HistoryItem*> item) {
const auto id = item->fullId();
auto i = _map.find(id);
if (i == _map.end()) {
load(item);
//_session->data().requestItemRepaint(item);
_session->data().requestItemResize(item);
} else if (!i->second.requestId) {
i->second.shown = !i->second.shown;
_session->data().requestItemResize(item);
}
}
const Transcribes::Entry &Transcribes::entry(
not_null<HistoryItem*> item) const {
static auto empty = Entry();
const auto i = _map.find(item->fullId());
return (i != _map.end()) ? i->second : empty;
}
void Transcribes::apply(const MTPDupdateTranscribeAudio &update) {
const auto id = update.vtranscription_id().v;
const auto i = _ids.find(id);
if (i == _ids.end()) {
return;
}
const auto j = _map.find(i->second);
if (j == _map.end()) {
return;
}
const auto text = qs(update.vtext());
j->second.result = text;
j->second.pending = !update.is_final();
if (const auto item = _session->data().message(i->second)) {
_session->data().requestItemResize(item);
}
}
void Transcribes::load(not_null<HistoryItem*> item) {
if (!item->isHistoryEntry() || item->isLocal()) {
return;
}
const auto id = item->fullId();
const auto requestId = _api.request(MTPmessages_TranscribeAudio(
item->history()->peer->input,
MTP_int(item->id)
)).done([=](const MTPmessages_TranscribedAudio &result) {
result.match([&](const MTPDmessages_transcribedAudio &data) {
auto &entry = _map[id];
entry.requestId = 0;
entry.pending = data.is_pending();
entry.result = qs(data.vtext());
_ids.emplace(data.vtranscription_id().v, id);
if (const auto item = _session->data().message(id)) {
_session->data().requestItemResize(item);
}
});
}).fail([=] {
auto &entry = _map[id];
entry.requestId = 0;
entry.pending = false;
entry.failed = true;
if (const auto item = _session->data().message(id)) {
_session->data().requestItemResize(item);
}
}).send();
auto &entry = _map.emplace(id).first->second;
entry.requestId = requestId;
entry.shown = true;
entry.failed = false;
entry.pending = false;
}
} // namespace Api

View file

@ -0,0 +1,48 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "mtproto/sender.h"
class ApiWrap;
namespace Main {
class Session;
} // namespace Main
namespace Api {
class Transcribes final {
public:
explicit Transcribes(not_null<ApiWrap*> api);
struct Entry {
QString result;
bool shown = false;
bool failed = false;
bool pending = false;
mtpRequestId requestId = 0;
};
void toggle(not_null<HistoryItem*> item);
[[nodiscard]] const Entry &entry(not_null<HistoryItem*> item) const;
void apply(const MTPDupdateTranscribeAudio &update);
private:
void load(not_null<HistoryItem*> item);
const not_null<Main::Session*> _session;
MTP::Sender _api;
base::flat_map<FullMsgId, Entry> _map;
base::flat_map<uint64, FullMsgId> _ids;
};
} // namespace Api

View file

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_text_entities.h"
#include "api/api_user_privacy.h"
#include "api/api_unread_things.h"
#include "api/api_transcribes.h"
#include "main/main_session.h"
#include "main/main_account.h"
#include "mtproto/mtp_instance.h"
@ -2387,6 +2388,11 @@ void Updates::feedUpdate(const MTPUpdate &update) {
session().api().ringtones().applyUpdate();
} break;
case mtpc_updateTranscribeAudio: {
const auto &data = update.c_updateTranscribeAudio();
_session->api().transcribes().apply(data);
}
}
}

View file

@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_confirm_phone.h"
#include "api/api_unread_things.h"
#include "api/api_ringtones.h"
#include "api/api_transcribes.h"
#include "data/notify/data_notify_settings.h"
#include "data/stickers/data_stickers.h"
#include "data/data_drafts.h"
@ -145,7 +146,8 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
, _polls(std::make_unique<Api::Polls>(this))
, _chatParticipants(std::make_unique<Api::ChatParticipants>(this))
, _unreadThings(std::make_unique<Api::UnreadThings>(this))
, _ringtones(std::make_unique<Api::Ringtones>(this)) {
, _ringtones(std::make_unique<Api::Ringtones>(this))
, _transcribes(std::make_unique<Api::Transcribes>(this)) {
crl::on_main(session, [=] {
// You can't use _session->lifetime() in the constructor,
// only queued, because it is not constructed yet.
@ -4105,3 +4107,7 @@ Api::UnreadThings &ApiWrap::unreadThings() {
Api::Ringtones &ApiWrap::ringtones() {
return *_ringtones;
}
Api::Transcribes &ApiWrap::transcribes() {
return *_transcribes;
}

View file

@ -70,6 +70,7 @@ class Polls;
class ChatParticipants;
class UnreadThings;
class Ringtones;
class Transcribes;
namespace details {
@ -361,6 +362,7 @@ public:
[[nodiscard]] Api::ChatParticipants &chatParticipants();
[[nodiscard]] Api::UnreadThings &unreadThings();
[[nodiscard]] Api::Ringtones &ringtones();
[[nodiscard]] Api::Transcribes &transcribes();
void updatePrivacyLastSeens();
@ -644,6 +646,7 @@ private:
const std::unique_ptr<Api::ChatParticipants> _chatParticipants;
const std::unique_ptr<Api::UnreadThings> _unreadThings;
const std::unique_ptr<Api::Ringtones> _ringtones;
const std::unique_ptr<Api::Transcribes> _transcribes;
mtpRequestId _wallPaperRequestId = 0;
QString _wallPaperSlug;

View file

@ -63,6 +63,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_streaming.h"
#include "data/data_media_rotation.h"
#include "data/data_histories.h"
#include "data/data_peer_values.h"
#include "base/platform/base_platform_info.h"
#include "base/unixtime.h"
#include "base/call_delayed.h"
@ -274,6 +275,20 @@ Session::Session(not_null<Main::Session*> session)
session->saveSettingsDelayed();
}
}, _lifetime);
crl::on_main(_session, [=] {
AmPremiumValue(
_session
) | rpl::start_with_next([=] {
for (const auto &[document, items] : _documentItems) {
if (document->isVoiceMessage()) {
for (const auto &item : items) {
requestItemResize(item);
}
}
}
}, _lifetime);
});
}
void Session::clear() {
@ -1175,7 +1190,6 @@ void Session::setupPeerNameViewer() {
const auto &oldLetters = update.oldFirstLetters;
_contactsNoChatsList.peerNameChanged(peer, oldLetters);
_contactsList.peerNameChanged(peer, oldLetters);
}, _lifetime);
}

View file

@ -937,3 +937,23 @@ void HistoryDocumentVoice::stopSeeking() {
_seeking = false;
Media::Player::instance()->cancelSeeking(AudioMsgId::Type::Voice);
}
bool HistoryDocumentVoice::seeking() const {
return _seeking;
}
float64 HistoryDocumentVoice::seekingStart() const {
return _seekingStart / kFloatToIntMultiplier;
}
void HistoryDocumentVoice::setSeekingStart(float64 seekingStart) const {
_seekingStart = qRound(seekingStart * kFloatToIntMultiplier);
}
float64 HistoryDocumentVoice::seekingCurrent() const {
return _seekingCurrent / kFloatToIntMultiplier;
}
void HistoryDocumentVoice::setSeekingCurrent(float64 seekingCurrent) {
_seekingCurrent = qRound(seekingCurrent * kFloatToIntMultiplier);
}

View file

@ -27,6 +27,7 @@ class Session;
namespace HistoryView {
class Element;
class Document;
class TranscribeButton;
} // namespace HistoryView
struct HistoryMessageVia : public RuntimeComponent<HistoryMessageVia, HistoryItem> {
@ -444,23 +445,16 @@ public:
std::shared_ptr<VoiceSeekClickHandler> _seekl;
mutable int _lastDurationMs = 0;
bool seeking() const {
return _seeking;
}
[[nodiscard]] bool seeking() const;
void startSeeking();
void stopSeeking();
float64 seekingStart() const {
return _seekingStart / kFloatToIntMultiplier;
}
void setSeekingStart(float64 seekingStart) const {
_seekingStart = qRound(seekingStart * kFloatToIntMultiplier);
}
float64 seekingCurrent() const {
return _seekingCurrent / kFloatToIntMultiplier;
}
void setSeekingCurrent(float64 seekingCurrent) {
_seekingCurrent = qRound(seekingCurrent * kFloatToIntMultiplier);
}
[[nodiscard]] float64 seekingStart() const;
void setSeekingStart(float64 seekingStart) const;
[[nodiscard]] float64 seekingCurrent() const;
void setSeekingCurrent(float64 seekingCurrent);
std::unique_ptr<HistoryView::TranscribeButton> transcribe;
Ui::Text::String transcribeText;
private:
bool _seeking = false;

View file

@ -0,0 +1,58 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/view/history_view_transcribe_button.h"
#include "history/history.h"
#include "history/history_item.h"
#include "data/data_session.h"
#include "main/main_session.h"
#include "ui/chat/chat_style.h"
#include "ui/click_handler.h"
#include "api/api_transcribes.h"
#include "apiwrap.h"
#include "styles/style_chat.h"
namespace HistoryView {
TranscribeButton::TranscribeButton(not_null<HistoryItem*> item)
: _item(item) {
}
QSize TranscribeButton::size() const {
return QSize(st::historyTranscribeSize, st::historyTranscribeSize);
}
void TranscribeButton::paint(
QPainter &p,
int x,
int y,
const PaintContext &context) {
auto hq = PainterHighQualityEnabler(p);
const auto stm = context.messageStyle();
p.setBrush(stm->msgWaveformInactive);
const auto radius = size().width() / 4;
p.drawRoundedRect(QRect{ QPoint(x, y), size() }, radius, radius);
}
ClickHandlerPtr TranscribeButton::link() {
if (!_item->isHistoryEntry() || _item->isLocal()) {
return nullptr;
} else if (_link) {
return _link;
}
const auto session = &_item->history()->session();
const auto id = _item->fullId();
_link = std::make_shared<LambdaClickHandler>([=] {
if (const auto item = session->data().message(id)) {
session->api().transcribes().toggle(item);
}
});
return _link;
}
} // namespace HistoryView

View file

@ -0,0 +1,38 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Ui {
struct ChatPaintContext;
} // namespace Ui
namespace HistoryView {
using PaintContext = Ui::ChatPaintContext;
class TranscribeButton final {
public:
explicit TranscribeButton(not_null<HistoryItem*> item);
[[nodiscard]] QSize size() const;
void paint(QPainter &p, int x, int y, const PaintContext &context);
[[nodiscard]] ClickHandlerPtr link();
private:
const not_null<HistoryItem*> _item;
ClickHandlerPtr _link;
QString _text;
bool _loaded = false;
bool _loading = false;
};
} // namespace HistoryView

View file

@ -9,12 +9,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "storage/localstorage.h"
#include "main/main_session.h"
#include "media/audio/media_audio.h"
#include "media/player/media_player_instance.h"
#include "history/history_item_components.h"
#include "history/history.h"
#include "history/view/history_view_element.h"
#include "history/view/history_view_cursor_state.h"
#include "history/view/history_view_transcribe_button.h"
#include "history/view/media/history_view_media_common.h"
#include "ui/image/image.h"
#include "ui/text/format_values.h"
@ -30,6 +32,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_media_types.h"
#include "data/data_file_click_handler.h"
#include "data/data_file_origin.h"
#include "api/api_transcribes.h"
#include "apiwrap.h"
#include "styles/style_chat.h"
namespace HistoryView {
@ -226,6 +230,41 @@ void Document::fillNamedFromData(HistoryDocumentNamed *named) {
QSize Document::countOptimalSize() {
auto captioned = Get<HistoryDocumentCaptioned>();
auto hasTranscribe = false;
const auto voice = Get<HistoryDocumentVoice>();
if (voice) {
const auto session = &_realParent->history()->session();
if (!session->premium()) {
voice->transcribe = nullptr;
voice->transcribeText = {};
} else {
if (!voice->transcribe) {
voice->transcribe = std::make_unique<TranscribeButton>(
_realParent);
}
const auto &entry = session->api().transcribes().entry(
_realParent);
auto text = entry.requestId
? "Transcribing..."
: entry.failed
? "Transcribing Failed."
: entry.shown
? ((entry.pending ? "Still Transcribing...\n" : "")
+ entry.result)
: QString();
if (text.isEmpty()) {
voice->transcribeText = {};
} else {
const auto minResizeWidth = st::minPhotoSize
- st::msgPadding.left()
- st::msgPadding.right();
voice->transcribeText = Ui::Text::String(minResizeWidth);
voice->transcribeText.setText(st::messageTextStyle, text);
hasTranscribe = true;
}
}
}
if (_parent->media() != this && !_realParent->groupId()) {
if (captioned) {
RemoveComponents(HistoryDocumentCaptioned::Bit());
@ -236,6 +275,7 @@ QSize Document::countOptimalSize() {
_parent->skipBlockWidth(),
_parent->skipBlockHeight());
}
auto thumbed = Get<HistoryDocumentThumbed>();
const auto &st = thumbed ? st::msgFileThumbLayout : st::msgFileLayout;
if (thumbed) {
@ -264,15 +304,30 @@ QSize Document::countOptimalSize() {
accumulate_max(maxWidth, tleft + named->_namew + tright);
accumulate_min(maxWidth, st::msgMaxWidth);
}
if (voice && voice->transcribe) {
maxWidth += st::historyTranscribeSkip
+ voice->transcribe->size().width();
}
auto minHeight = st.padding.top() + st.thumbSize + st.padding.bottom();
if (!captioned && _parent->bottomInfoIsWide()) {
if (!captioned && !hasTranscribe && _parent->bottomInfoIsWide()) {
minHeight += st::msgDateFont->height - st::msgDateDelta.y();
}
if (!isBubbleTop()) {
minHeight -= st::msgFileTopMinus;
}
if (hasTranscribe) {
auto captionw = maxWidth
- st::msgPadding.left()
- st::msgPadding.right();
minHeight += voice->transcribeText.countHeight(captionw);
if (captioned) {
minHeight += st::mediaCaptionSkip;
} else if (isBubbleBottom()) {
minHeight += st::msgPadding.bottom();
}
}
if (captioned) {
auto captionw = maxWidth
- st::msgPadding.left()
@ -287,7 +342,9 @@ QSize Document::countOptimalSize() {
QSize Document::countCurrentSize(int newWidth) {
const auto captioned = Get<HistoryDocumentCaptioned>();
if (!captioned) {
const auto voice = Get<HistoryDocumentVoice>();
const auto hasTranscribe = voice && !voice->transcribeText.isEmpty();
if (!captioned && !hasTranscribe) {
return File::countCurrentSize(newWidth);
}
@ -299,9 +356,19 @@ QSize Document::countCurrentSize(int newWidth) {
newHeight -= st::msgFileTopMinus;
}
auto captionw = newWidth - st::msgPadding.left() - st::msgPadding.right();
newHeight += captioned->_caption.countHeight(captionw);
if (isBubbleBottom()) {
newHeight += st::msgPadding.bottom();
if (hasTranscribe) {
newHeight += voice->transcribeText.countHeight(captionw);
if (captioned) {
newHeight += st::mediaCaptionSkip;
} else if (isBubbleBottom()) {
newHeight += st::msgPadding.bottom();
}
}
if (captioned) {
newHeight += captioned->_caption.countHeight(captionw);
if (isBubbleBottom()) {
newHeight += st::msgPadding.bottom();
}
}
return { newWidth, newHeight };
@ -498,7 +565,8 @@ void Document::draw(
auto statuswidth = namewidth;
auto voiceStatusOverride = QString();
if (const auto voice = Get<HistoryDocumentVoice>()) {
const auto voice = Get<HistoryDocumentVoice>();
if (voice) {
ensureDataMediaCreated();
if (const auto voiceData = _data->voice()) {
@ -527,9 +595,19 @@ void Document::draw(
base::SafeRound(progress * voice->_lastDurationMs) / 1000,
voice->_lastDurationMs / 1000);
}
if (voice->transcribe) {
const auto size = voice->transcribe->size();
namewidth -= st::historyTranscribeSkip + size.width();
const auto x = nameleft + namewidth + st::historyTranscribeSkip;
const auto y = st.padding.top()
- topMinus
+ st::msgWaveformMax
- size.height();
voice->transcribe->paint(p, x, y, context);
}
p.save();
p.translate(nameleft, st.padding.top() - topMinus);
PaintWaveform(p,
context,
_data->voice(),
@ -564,9 +642,15 @@ void Document::draw(
}
}
auto captiontop = bottom;
if (voice && !voice->transcribeText.isEmpty()) {
p.setPen(stm->historyTextFg);
voice->transcribeText.draw(p, st::msgPadding.left(), bottom, captionw, style::al_left, 0, -1, context.selection);
captiontop += voice->transcribeText.countHeight(captionw) + st::mediaCaptionSkip;
}
if (auto captioned = Get<HistoryDocumentCaptioned>()) {
p.setPen(stm->historyTextFg);
captioned->_caption.draw(p, st::msgPadding.left(), bottom, captionw, style::al_left, 0, -1, context.selection);
captioned->_caption.draw(p, st::msgPadding.left(), captiontop, captionw, style::al_left, 0, -1, context.selection);
}
}
@ -745,9 +829,23 @@ TextState Document::textState(
}
}
if (const auto voice = Get<HistoryDocumentVoice>()) {
auto namewidth = width - nameleft - nameright;
const auto voice = Get<HistoryDocumentVoice>();
auto namewidth = width - nameleft - nameright;
if (voice) {
auto waveformbottom = st.padding.top() - topMinus + st::msgWaveformMax + st::msgWaveformMin;
if (voice->transcribe) {
const auto size = voice->transcribe->size();
namewidth -= st::historyTranscribeSkip + size.width();
const auto x = nameleft + namewidth + st::historyTranscribeSkip;
const auto y = st.padding.top()
- topMinus
+ st::msgWaveformMax
- size.height();
if (QRect(QPoint(x, y), size).contains(point)) {
result.link = voice->transcribe->link();
return result;
}
}
if (QRect(nameleft, nametop, namewidth, waveformbottom - nametop).contains(point)) {
const auto state = ::Media::Player::instance()->getState(AudioMsgId::Type::Voice);
if (state.id == AudioMsgId(_data, _realParent->fullId(), state.id.externalPlayId())
@ -776,7 +874,8 @@ TextState Document::textState(
painth -= st::msgPadding.bottom();
}
}
if (QRect(0, 0, width, painth).contains(point)
const auto till = voice ? (nameleft + namewidth) : width;
if (QRect(0, 0, till, painth).contains(point)
&& (!_data->loading() || downloadInCorner())
&& !_data->uploading()
&& !_data->isNull()) {

View file

@ -655,6 +655,9 @@ msgWaveformSkip: 1px;
msgWaveformMin: 2px;
msgWaveformMax: 20px;
historyTranscribeSkip: 10px;
historyTranscribeSize: 24px;
historyVideoMessageMute: icon {{ "volume_mute", historyFileThumbIconFg }};
historyVideoMessageMuteSelected: icon {{ "volume_mute", historyFileThumbIconFgSelected }};
historyVideoMessageMuteSize: 25px;