mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Allow selecting / copying voice transcribe text.
This commit is contained in:
parent
1467b1c720
commit
0fc687953f
2 changed files with 132 additions and 25 deletions
|
@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/emoji_config.h"
|
#include "ui/emoji_config.h"
|
||||||
#include "api/api_sending.h"
|
#include "api/api_sending.h"
|
||||||
|
#include "api/api_transcribes.h"
|
||||||
#include "storage/storage_shared_media.h"
|
#include "storage/storage_shared_media.h"
|
||||||
#include "storage/localstorage.h"
|
#include "storage/localstorage.h"
|
||||||
#include "chat_helpers/stickers_dice_pack.h" // Stickers::DicePacks::IsSlot.
|
#include "chat_helpers/stickers_dice_pack.h" // Stickers::DicePacks::IsSlot.
|
||||||
|
@ -56,6 +57,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "storage/file_upload.h"
|
#include "storage/file_upload.h"
|
||||||
#include "window/window_session_controller.h" // Window::Show
|
#include "window/window_session_controller.h" // Window::Show
|
||||||
|
#include "apiwrap.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
|
|
||||||
|
@ -858,9 +860,27 @@ TextForMimeData MediaFile::clipboardText() const {
|
||||||
}
|
}
|
||||||
return tr::lng_in_dlg_file(tr::now) + addName;
|
return tr::lng_in_dlg_file(tr::now) + addName;
|
||||||
}();
|
}();
|
||||||
return WithCaptionClipboardText(
|
auto caption = parent()->clipboardText();
|
||||||
attachType,
|
|
||||||
parent()->clipboardText());
|
if (_document->isVoiceMessage()) {
|
||||||
|
const auto &entry = _document->session().api().transcribes().entry(
|
||||||
|
parent());
|
||||||
|
if (!entry.requestId
|
||||||
|
&& entry.shown
|
||||||
|
&& !entry.toolong
|
||||||
|
&& !entry.failed
|
||||||
|
&& (entry.pending || !entry.result.isEmpty())) {
|
||||||
|
const auto text = "{{\n"
|
||||||
|
+ entry.result
|
||||||
|
+ (entry.result.isEmpty() ? "" : " ")
|
||||||
|
+ (entry.pending ? "[...]" : "")
|
||||||
|
+ "\n}}"
|
||||||
|
+ (caption.rich.text.isEmpty() ? "" : "\n");
|
||||||
|
caption = TextForMimeData{ text, { text } }.append(std::move(caption));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return WithCaptionClipboardText(attachType, std::move(caption));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaFile::allowsEditCaption() const {
|
bool MediaFile::allowsEditCaption() const {
|
||||||
|
|
|
@ -235,6 +235,17 @@ void Document::fillNamedFromData(HistoryDocumentNamed *named) {
|
||||||
|
|
||||||
QSize Document::countOptimalSize() {
|
QSize Document::countOptimalSize() {
|
||||||
auto captioned = Get<HistoryDocumentCaptioned>();
|
auto captioned = Get<HistoryDocumentCaptioned>();
|
||||||
|
if (_parent->media() != this && !_realParent->groupId()) {
|
||||||
|
if (captioned) {
|
||||||
|
RemoveComponents(HistoryDocumentCaptioned::Bit());
|
||||||
|
captioned = nullptr;
|
||||||
|
}
|
||||||
|
} else if (captioned && captioned->_caption.hasSkipBlock()) {
|
||||||
|
captioned->_caption.updateSkipBlock(
|
||||||
|
_parent->skipBlockWidth(),
|
||||||
|
_parent->skipBlockHeight());
|
||||||
|
}
|
||||||
|
|
||||||
auto hasTranscribe = false;
|
auto hasTranscribe = false;
|
||||||
const auto voice = Get<HistoryDocumentVoice>();
|
const auto voice = Get<HistoryDocumentVoice>();
|
||||||
if (voice) {
|
if (voice) {
|
||||||
|
@ -277,21 +288,17 @@ QSize Document::countOptimalSize() {
|
||||||
st::messageTextStyle,
|
st::messageTextStyle,
|
||||||
text);
|
text);
|
||||||
hasTranscribe = true;
|
hasTranscribe = true;
|
||||||
|
if (const auto skipBlockWidth = captioned
|
||||||
|
? 0
|
||||||
|
: _parent->skipBlockWidth()) {
|
||||||
|
voice->transcribeText.updateSkipBlock(
|
||||||
|
skipBlockWidth,
|
||||||
|
_parent->skipBlockHeight());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_parent->media() != this && !_realParent->groupId()) {
|
|
||||||
if (captioned) {
|
|
||||||
RemoveComponents(HistoryDocumentCaptioned::Bit());
|
|
||||||
captioned = nullptr;
|
|
||||||
}
|
|
||||||
} else if (captioned && captioned->_caption.hasSkipBlock()) {
|
|
||||||
captioned->_caption.updateSkipBlock(
|
|
||||||
_parent->skipBlockWidth(),
|
|
||||||
_parent->skipBlockHeight());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto thumbed = Get<HistoryDocumentThumbed>();
|
auto thumbed = Get<HistoryDocumentThumbed>();
|
||||||
const auto &st = thumbed ? st::msgFileThumbLayout : st::msgFileLayout;
|
const auto &st = thumbed ? st::msgFileThumbLayout : st::msgFileLayout;
|
||||||
if (thumbed) {
|
if (thumbed) {
|
||||||
|
@ -655,15 +662,17 @@ void Document::draw(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto selection = context.selection;
|
||||||
auto captiontop = bottom;
|
auto captiontop = bottom;
|
||||||
if (voice && !voice->transcribeText.isEmpty()) {
|
if (voice && !voice->transcribeText.isEmpty()) {
|
||||||
p.setPen(stm->historyTextFg);
|
p.setPen(stm->historyTextFg);
|
||||||
voice->transcribeText.draw(p, st::msgPadding.left(), bottom, captionw, style::al_left, 0, -1, context.selection);
|
voice->transcribeText.draw(p, st::msgPadding.left(), bottom, captionw, style::al_left, 0, -1, selection);
|
||||||
captiontop += voice->transcribeText.countHeight(captionw) + st::mediaCaptionSkip;
|
captiontop += voice->transcribeText.countHeight(captionw) + st::mediaCaptionSkip;
|
||||||
|
selection = HistoryView::UnshiftItemSelection(selection, voice->transcribeText);
|
||||||
}
|
}
|
||||||
if (auto captioned = Get<HistoryDocumentCaptioned>()) {
|
if (const auto captioned = Get<HistoryDocumentCaptioned>()) {
|
||||||
p.setPen(stm->historyTextFg);
|
p.setPen(stm->historyTextFg);
|
||||||
captioned->_caption.draw(p, st::msgPadding.left(), captiontop, captionw, style::al_left, 0, -1, context.selection);
|
captioned->_caption.draw(p, st::msgPadding.left(), captiontop, captionw, style::al_left, 0, -1, selection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -812,7 +821,7 @@ TextState Document::textState(
|
||||||
const auto nametop = st.nameTop - topMinus;
|
const auto nametop = st.nameTop - topMinus;
|
||||||
const auto nameright = st.padding.left();
|
const auto nameright = st.padding.left();
|
||||||
const auto linktop = st.linkTop - topMinus;
|
const auto linktop = st.linkTop - topMinus;
|
||||||
const auto bottom = st.padding.top() + st.thumbSize + st.padding.bottom() - topMinus;
|
auto bottom = st.padding.top() + st.thumbSize + st.padding.bottom() - topMinus;
|
||||||
const auto rthumb = style::rtlrect(st.padding.left(), st.padding.top() - topMinus, st.thumbSize, st.thumbSize, width);
|
const auto rthumb = style::rtlrect(st.padding.left(), st.padding.top() - topMinus, st.thumbSize, st.thumbSize, width);
|
||||||
const auto innerSize = st::msgFileLayout.thumbSize;
|
const auto innerSize = st::msgFileLayout.thumbSize;
|
||||||
const auto inner = QRect(rthumb.x() + (rthumb.width() - innerSize) / 2, rthumb.y() + (rthumb.height() - innerSize) / 2, innerSize, innerSize);
|
const auto inner = QRect(rthumb.x() + (rthumb.width() - innerSize) / 2, rthumb.y() + (rthumb.height() - innerSize) / 2, innerSize, innerSize);
|
||||||
|
@ -844,6 +853,9 @@ TextState Document::textState(
|
||||||
|
|
||||||
const auto voice = Get<HistoryDocumentVoice>();
|
const auto voice = Get<HistoryDocumentVoice>();
|
||||||
auto namewidth = width - nameleft - nameright;
|
auto namewidth = width - nameleft - nameright;
|
||||||
|
auto transcribeLength = 0;
|
||||||
|
auto transcribeHeight = 0;
|
||||||
|
auto painth = layout.height();
|
||||||
if (voice) {
|
if (voice) {
|
||||||
auto waveformbottom = st.padding.top() - topMinus + st::msgWaveformMax + st::msgWaveformMin;
|
auto waveformbottom = st.padding.top() - topMinus + st::msgWaveformMax + st::msgWaveformMin;
|
||||||
if (voice->transcribe) {
|
if (voice->transcribe) {
|
||||||
|
@ -867,15 +879,36 @@ TextState Document::textState(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
transcribeLength = voice->transcribeText.length();
|
||||||
|
if (transcribeLength > 0) {
|
||||||
|
auto captionw = width - st::msgPadding.left() - st::msgPadding.right();
|
||||||
|
transcribeHeight = voice->transcribeText.countHeight(captionw);
|
||||||
|
painth -= transcribeHeight;
|
||||||
|
if (point.y() >= bottom && point.y() < bottom + transcribeHeight) {
|
||||||
|
result = TextState(_parent, voice->transcribeText.getState(
|
||||||
|
point - QPoint(st::msgPadding.left(), bottom),
|
||||||
|
width - st::msgPadding.left() - st::msgPadding.right(),
|
||||||
|
request.forText()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
bottom += transcribeHeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto painth = layout.height();
|
|
||||||
if (const auto captioned = Get<HistoryDocumentCaptioned>()) {
|
if (const auto captioned = Get<HistoryDocumentCaptioned>()) {
|
||||||
|
if (point.y() >= bottom) {
|
||||||
|
result.symbol += transcribeLength;
|
||||||
|
}
|
||||||
|
if (transcribeHeight) {
|
||||||
|
painth -= st::mediaCaptionSkip;
|
||||||
|
bottom += st::mediaCaptionSkip;
|
||||||
|
}
|
||||||
if (point.y() >= bottom) {
|
if (point.y() >= bottom) {
|
||||||
result = TextState(_parent, captioned->_caption.getState(
|
result = TextState(_parent, captioned->_caption.getState(
|
||||||
point - QPoint(st::msgPadding.left(), bottom),
|
point - QPoint(st::msgPadding.left(), bottom),
|
||||||
width - st::msgPadding.left() - st::msgPadding.right(),
|
width - st::msgPadding.left() - st::msgPadding.right(),
|
||||||
request.forText()));
|
request.forText()));
|
||||||
|
result.symbol += transcribeLength;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
auto captionw = width - st::msgPadding.left() - st::msgPadding.right();
|
auto captionw = width - st::msgPadding.left() - st::msgPadding.right();
|
||||||
|
@ -883,6 +916,8 @@ TextState Document::textState(
|
||||||
if (isBubbleBottom()) {
|
if (isBubbleBottom()) {
|
||||||
painth -= st::msgPadding.bottom();
|
painth -= st::msgPadding.bottom();
|
||||||
}
|
}
|
||||||
|
} else if (transcribeHeight && isBubbleBottom()) {
|
||||||
|
painth -= st::msgPadding.bottom();
|
||||||
}
|
}
|
||||||
const auto till = voice ? (nameleft + namewidth) : width;
|
const auto till = voice ? (nameleft + namewidth) : width;
|
||||||
if (QRect(0, 0, till, painth).contains(point)
|
if (QRect(0, 0, till, painth).contains(point)
|
||||||
|
@ -901,7 +936,7 @@ TextState Document::textState(
|
||||||
|
|
||||||
void Document::updatePressed(QPoint point) {
|
void Document::updatePressed(QPoint point) {
|
||||||
// LayoutMode should be passed here.
|
// LayoutMode should be passed here.
|
||||||
if (auto voice = Get<HistoryDocumentVoice>()) {
|
if (const auto voice = Get<HistoryDocumentVoice>()) {
|
||||||
if (voice->seeking()) {
|
if (voice->seeking()) {
|
||||||
const auto thumbed = Get<HistoryDocumentThumbed>();
|
const auto thumbed = Get<HistoryDocumentThumbed>();
|
||||||
const auto &st = thumbed ? st::msgFileThumbLayout : st::msgFileLayout;
|
const auto &st = thumbed ? st::msgFileThumbLayout : st::msgFileLayout;
|
||||||
|
@ -920,28 +955,80 @@ void Document::updatePressed(QPoint point) {
|
||||||
TextSelection Document::adjustSelection(
|
TextSelection Document::adjustSelection(
|
||||||
TextSelection selection,
|
TextSelection selection,
|
||||||
TextSelectType type) const {
|
TextSelectType type) const {
|
||||||
|
auto transcribe = (const Ui::Text::String*)nullptr;
|
||||||
|
auto caption = (const Ui::Text::String*)nullptr;
|
||||||
|
if (const auto voice = Get<HistoryDocumentVoice>()) {
|
||||||
|
transcribe = &voice->transcribeText;
|
||||||
|
}
|
||||||
if (const auto captioned = Get<HistoryDocumentCaptioned>()) {
|
if (const auto captioned = Get<HistoryDocumentCaptioned>()) {
|
||||||
return captioned->_caption.adjustSelection(selection, type);
|
caption = &captioned->_caption;
|
||||||
|
}
|
||||||
|
const auto transcribeLength = transcribe ? transcribe->length() : 0;
|
||||||
|
if (transcribe && selection.from < transcribeLength) {
|
||||||
|
const auto adjusted = transcribe->adjustSelection(selection, type);
|
||||||
|
if (selection.to <= transcribeLength) {
|
||||||
|
return adjusted;
|
||||||
|
}
|
||||||
|
selection = TextSelection(adjusted.from, selection.to);
|
||||||
|
}
|
||||||
|
if (caption && selection.to > transcribeLength) {
|
||||||
|
auto unshifted = transcribe
|
||||||
|
? HistoryView::UnshiftItemSelection(selection, *transcribe)
|
||||||
|
: selection;
|
||||||
|
const auto adjusted = caption->adjustSelection(unshifted, type);
|
||||||
|
const auto shifted = transcribe
|
||||||
|
? HistoryView::ShiftItemSelection(adjusted, *transcribe)
|
||||||
|
: adjusted;
|
||||||
|
if (selection.from >= transcribeLength) {
|
||||||
|
return shifted;
|
||||||
|
}
|
||||||
|
selection = TextSelection(selection.from, shifted.to);
|
||||||
}
|
}
|
||||||
return selection;
|
return selection;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 Document::fullSelectionLength() const {
|
uint16 Document::fullSelectionLength() const {
|
||||||
|
auto result = uint16();
|
||||||
|
if (const auto voice = Get<HistoryDocumentVoice>()) {
|
||||||
|
result += voice->transcribeText.length();
|
||||||
|
}
|
||||||
if (const auto captioned = Get<HistoryDocumentCaptioned>()) {
|
if (const auto captioned = Get<HistoryDocumentCaptioned>()) {
|
||||||
return captioned->_caption.length();
|
result += captioned->_caption.length();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Document::hasTextForCopy() const {
|
bool Document::hasTextForCopy() const {
|
||||||
|
if (const auto voice = Get<HistoryDocumentVoice>()) {
|
||||||
|
if (!voice->transcribeText.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return Has<HistoryDocumentCaptioned>();
|
return Has<HistoryDocumentCaptioned>();
|
||||||
}
|
}
|
||||||
|
|
||||||
TextForMimeData Document::selectedText(TextSelection selection) const {
|
TextForMimeData Document::selectedText(TextSelection selection) const {
|
||||||
if (const auto captioned = Get<HistoryDocumentCaptioned>()) {
|
auto result = TextForMimeData();
|
||||||
return captioned->_caption.toTextForMimeData(selection);
|
if (const auto voice = Get<HistoryDocumentVoice>()) {
|
||||||
|
const auto length = voice->transcribeText.length();
|
||||||
|
if (selection.from < length) {
|
||||||
|
result.append(
|
||||||
|
voice->transcribeText.toTextForMimeData(selection));
|
||||||
|
}
|
||||||
|
if (selection.to <= length) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
selection = HistoryView::UnshiftItemSelection(
|
||||||
|
selection,
|
||||||
|
voice->transcribeText);
|
||||||
}
|
}
|
||||||
return TextForMimeData();
|
if (const auto captioned = Get<HistoryDocumentCaptioned>()) {
|
||||||
|
if (!result.empty()) {
|
||||||
|
result.append("\n\n");
|
||||||
|
}
|
||||||
|
result.append(captioned->_caption.toTextForMimeData(selection));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Document::uploading() const {
|
bool Document::uploading() const {
|
||||||
|
|
Loading…
Add table
Reference in a new issue