From e5d95c0ab012bc35cbf4282baa163fab33be938c Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 25 May 2022 16:18:49 +0400 Subject: [PATCH] Improve voice transcribe design. --- .../Resources/icons/chat/voice_to_text.png | Bin 0 -> 494 bytes .../Resources/icons/chat/voice_to_text@2x.png | Bin 0 -> 816 bytes .../Resources/icons/chat/voice_to_text@3x.png | Bin 0 -> 1141 bytes .../icons/chat/voice_to_text_collapse.png | Bin 0 -> 259 bytes .../icons/chat/voice_to_text_collapse@2x.png | Bin 0 -> 360 bytes .../icons/chat/voice_to_text_collapse@3x.png | Bin 0 -> 471 bytes .../view/history_view_transcribe_button.cpp | 102 +++++++++++++++++- .../view/history_view_transcribe_button.h | 10 +- .../view/media/history_view_document.cpp | 46 ++++---- Telegram/SourceFiles/ui/chat/chat.style | 15 ++- Telegram/SourceFiles/ui/chat/chat_style.cpp | 12 +++ Telegram/SourceFiles/ui/chat/chat_style.h | 3 + 12 files changed, 159 insertions(+), 29 deletions(-) create mode 100644 Telegram/Resources/icons/chat/voice_to_text.png create mode 100644 Telegram/Resources/icons/chat/voice_to_text@2x.png create mode 100644 Telegram/Resources/icons/chat/voice_to_text@3x.png create mode 100644 Telegram/Resources/icons/chat/voice_to_text_collapse.png create mode 100644 Telegram/Resources/icons/chat/voice_to_text_collapse@2x.png create mode 100644 Telegram/Resources/icons/chat/voice_to_text_collapse@3x.png diff --git a/Telegram/Resources/icons/chat/voice_to_text.png b/Telegram/Resources/icons/chat/voice_to_text.png new file mode 100644 index 0000000000000000000000000000000000000000..b677a7c5e54976605ac37a4ec441684d4c67d242 GIT binary patch literal 494 zcmeAS@N?(olHy`uVBq!ia0vp^GC(ZG!2~2@zGN>2QjEnx?oJHr&dIz4a$Hg)JkxxA z8MJ_G4hF{dOa>N^5+IfWVg?501&j>LK$;OGwtxvPE3<$Z&K3hH)Z={vRL2Eak- zA^3LE#=fQi0oPcL83}JVrf%G@Xz|5aw^|N4C7C^xR=E-)P#!1G;#K|@BQ z*u6Tdxv#!jSynGji0oRl=YPwxOh*Bcn65=!ud}uuI&3|+FLPGL%2id(3fz&?9`2T& zq;l~5=RZ%2BG+F(ar>>=i+Rr{&e@*LY5w;6@3U!}1p@nyKaN}9ew(-5Ss}nrZL*1P zp@Gc~yCY$%OD$y9S@M70ZGAV#?D^-L-~aZnzwx$gfppu)2|<|?;^ReJ6~ww-U*?!d z1&ZWuza6AG>HXL6kSRa%pMCzBVd6Du$%`Tx_LkSXmRj~DS42$Hof`h>)&X@c-@`i! SZ1ZM=!rIf-&t;ucLK6VOAIBm9 literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/chat/voice_to_text@2x.png b/Telegram/Resources/icons/chat/voice_to_text@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..224b40bb369d3356ae4e386bab3ee5cdcd95e7a9 GIT binary patch literal 816 zcmeAS@N?(olHy`uVBq!ia0vp^7C@}S!2~4tFMe|bNHG=%xjQkeJ16rJ$Z<)H@J#dd zWzYh$IT#q*GZ|PwN`P1jh#44|7cep~18GK(*a9ZFti=LmI9ms#aE5uLAOi!_EKe85 zkO9d0YkW_zqV^=rrXBX{QRDZDQ6eqG+O%JXL`&sqAvQUP~Y8#2X$>`dDK1 z_p@Qy?zv~vb_;!WHJ{+}^w{H#QEQi-5#wRA_xSgFnwRRSh*Ivy^cQK#c z8>02pvq_DoOyI2 z%_rxxq(1SDX+Nx(1XQC?uQ%QK^5KUIuD{mQ{?r~=wDtDeh;!4Yi?8_pp#0QX8@ad?p-nHfNig`D4+}w8GjnkVx z-Q&T$)Qu4>PImtvENP`uKht=|48KJUox_(pw#N=>gTe~DWM4fgEm$B literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/chat/voice_to_text@3x.png b/Telegram/Resources/icons/chat/voice_to_text@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..731ba5aad67076825e1b7088ab7666f5c683b14f GIT binary patch literal 1141 zcmeAS@N?(olHy`uVBq!ia0vp^AwcZJ!2~4T+R_Ao6k~CayA#8@b22Z19GBDx&op0O z1}z|)gMqOEakt z!T2`P+C$q>{&;>7cVlH6lZh=hiGI zCl+p3$AgEQa{s7`b?yIA`92|T+Ub;V_1%+mx_0}%J9nr0`5fcTpS=SG?bk49AK==+ zgq?CYs2vdVfulPsJNx&qU$bV-I(P1z)4~g9&-y-04r?x`sQB^l;luo2o+?7k&COXs ztIs|v+r50hyo8t0_AOiX?A^Px^Z)AJ_fVKI>%4q-R&&T)!SZ{dB5qZRb~!U6QL-uU4MeA^J~Q zS^4SHr@KySYiYH$wUw-Xqv_(FxFvh;WTQ1-{y%)Ec=p@Zudeas<>hZ5W?s?yC7Gk? za^u;L@{$sc%4g4?w+iXhxp} zzRr7VYip_A=4R$o^{J_@t53B*EU;MhWZt@UdcvRMpMA2kvs))Pd(NCCPvqt0wY9ak z-jb0zd-iN~b@ic1&I>(m1uR*&?i|O9BS%=ye*W_1Nr{!|b6{A1|6cyez|3sf)n^wN zif^qFtu8IS%CW*=L-WA}4|eX{={ft}y?bIZSN2bvHm$Cv=0e!o8}9Dzy9A=6qg%Jw z+S)cfKX8EI>(4)bj?4`I5cq#q`#gRYrYSd`K27!P+`)MK-nW1M=IuIr=FEz8?UazO zXYb#=`?BtHYHI5B>({4ybIHrd)3N1Gm$dH#9&bn#Q_+R~dDo;CTX{M0kN zbz8Fcn~2^1`~Ek%x-HilZF;-^w()V9KZ`GFq>A#j|NrytNRpw{rmb72zOP&Mc4k^! ze7t^+OkudM@#|ZQ7cZV-!^Zuse%CxpeUn`$e^zc;o{+e3nMuLCqno~KC%t*Kk?Ycd zl`B`qFD`nd5R z%E5;={>d8|kDJ99g)NnC+go;a%GbP0l+XkKuw)YW literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/chat/voice_to_text_collapse.png b/Telegram/Resources/icons/chat/voice_to_text_collapse.png new file mode 100644 index 0000000000000000000000000000000000000000..752f8be2fe586084ec7603eb6b350fde6bdaaf80 GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^GC(ZG!2~2@zGN>2QjEnx?oJHr&dIz4a$Hg)JkxxA z8MJ_G4hF{dOa>N^5+IfWVg?501&j>LK$;OGwtxvPE3<$Z&K3hH)Z={vQkU!L;uvBf zn4BQNx>(UbLGi)+_wS!SclTW_EhY7@nQ?-nY_XzR924_`lOYD;d5btC7<`vqiAfPw z+{ZS{XW~v(RaFOf#$E=g7MZ?+;zq6sM>~_&$L;;~<>loJwL^Egr!Z+LoLUg*3N+ip ZnSmjI)#q4fYP>GU0iLdYF6*2UngE-3KePY< literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/chat/voice_to_text_collapse@2x.png b/Telegram/Resources/icons/chat/voice_to_text_collapse@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..da161b7338abc86fd51d5136f9067dbf53c37205 GIT binary patch literal 360 zcmeAS@N?(olHy`uVBq!ia0vp^7C@}S!2~4tFMe|bNHG=%xjQkeJ16rJ$Z<)H@J#dd zWzYh$IT#q*GZ|PwN`P1jh#44|7cep~18GK(*a9ZFti=LmI9ms#aE5uLAdtG`>Eaj? z!TEObLEgg(Jg%3$zbCQmV)Qw{rE|FM?bh~do0f7kW-SysY4@jo#iXXU%a{MK5RhnK zgd=Ze^FGysr``men(WN4{XO^Hl_>kz7gyVy=UWAEZLq#J@6%b!vsOv68uBuWz8D-aE;wq_vpMHWmz6GDDk$~0{KncTlj`aZXJ-34T-Qv^ zI`8Fcw%~=X6NkQEPvCyb`9Ymmf+qhg`EOr-ZtK4PSK?-OXu%x=WSnQ)*MHC~`IT?b Qb&xMTUHx3vIVCg!0Jx@mQvd(} literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/chat/voice_to_text_collapse@3x.png b/Telegram/Resources/icons/chat/voice_to_text_collapse@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..204ffcbac71506127d6a373b1c055f0438a66038 GIT binary patch literal 471 zcmeAS@N?(olHy`uVBq!ia0vp^AwcZJ!2~4T+R_Ao6k~CayA#8@b22Z19GBDx&op0O z1}z|)gMqO^u~%Eb@x{Nr(N5ag&aAm(!)+`{dgcuS#$htzIQ{{A03L-jnnu#Yrw^ zzR4T!uD0PP(w;fLgX>ni{CJ`sPm{&iJV(rH7r_L)n$_WwF(-^r0*bZ2(u zy#L*I_})IAzToi+rpe2)`)}`*Ha}f|?CJE>mw9#8JM;ewJ>jxCU3+_5esJt{*P7>c zJejJzx#^uB_D=iv^YRtB;y2eT`!ip5Vt5b9(;Y@1SeHldzNPm3GAIfdJYD@<);T3K F0RZ~Nr_=xd literal 0 HcmV?d00001 diff --git a/Telegram/SourceFiles/history/view/history_view_transcribe_button.cpp b/Telegram/SourceFiles/history/view/history_view_transcribe_button.cpp index 5284f43c2c..217563dc40 100644 --- a/Telegram/SourceFiles/history/view/history_view_transcribe_button.cpp +++ b/Telegram/SourceFiles/history/view/history_view_transcribe_button.cpp @@ -13,18 +13,42 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "ui/chat/chat_style.h" #include "ui/click_handler.h" +#include "ui/effects/radial_animation.h" #include "api/api_transcribes.h" #include "apiwrap.h" #include "styles/style_chat.h" namespace HistoryView { +namespace { + +constexpr auto kInNonChosenOpacity = 0.12; +constexpr auto kOutNonChosenOpacity = 0.18; + +} // namespace TranscribeButton::TranscribeButton(not_null item) : _item(item) { } +TranscribeButton::~TranscribeButton() = default; + QSize TranscribeButton::size() const { - return QSize(st::historyTranscribeSize, st::historyTranscribeSize); + return st::historyTranscribeSize; +} + +void TranscribeButton::setLoading(bool loading, Fn update) { + if (_loading == loading) { + return; + } + _loading = loading; + if (_loading) { + _animation = std::make_unique( + update, + st::defaultInfiniteRadialAnimation); + _animation->start(); + } else if (_animation) { + _animation->stop(); + } } void TranscribeButton::paint( @@ -33,10 +57,80 @@ void TranscribeButton::paint( int y, const PaintContext &context) { auto hq = PainterHighQualityEnabler(p); + const auto opened = _openedAnimation.value(_opened ? 1. : 0.); const auto stm = context.messageStyle(); - p.setBrush(stm->msgWaveformInactive); - const auto radius = size().width() / 4; - p.drawRoundedRect(QRect{ QPoint(x, y), size() }, radius, radius); + auto bg = stm->msgFileBg->c; + bg.setAlphaF(bg.alphaF() * (context.outbg + ? kOutNonChosenOpacity + : kInNonChosenOpacity)); + p.setBrush(bg); + const auto radius = st::historyTranscribeRadius; + const auto state = _animation + ? _animation->computeState() + : Ui::RadialState(); + if (state.shown > 0.) { + auto fg = stm->msgWaveformActive->c; + fg.setAlphaF(fg.alphaF() * state.shown * (1. - opened)); + auto pen = QPen(fg); + const auto thickness = style::ConvertScaleExact(2.); + const auto widthNoRadius = size().width() - 2 * radius; + const auto heightNoRadius = size().height() - 2 * radius; + const auto length = 2 * (widthNoRadius + heightNoRadius) + + 2 * M_PI * radius; + pen.setWidthF(thickness); + pen.setCapStyle(Qt::RoundCap); + const auto ratio = length / (Ui::RadialState::kFull * thickness); + const auto filled = ratio * state.arcLength; + pen.setDashPattern({ filled, (length / thickness) - filled }); + pen.setDashOffset(ratio * (state.arcFrom + state.arcLength)); + p.setPen(pen); + } else { + p.setPen(Qt::NoPen); + if (!_loading) { + _animation = nullptr; + } + } + const auto r = QRect{ QPoint(x, y), size() }; + p.drawRoundedRect(r, radius, radius); + if (opened > 0.) { + if (opened != 1.) { + p.save(); + p.setOpacity(opened); + p.translate(r.center()); + p.scale(opened, opened); + p.translate(-r.center()); + } + stm->historyTranscribeHide.paintInCenter(p, r); + if (opened != 1.) { + p.restore(); + } + } + if (opened < 1.) { + if (opened != 0.) { + p.save(); + p.setOpacity(1. - opened); + p.translate(r.center()); + p.scale(1. - opened, 1. - opened); + p.translate(-r.center()); + } + stm->historyTranscribeIcon.paintInCenter(p, r); + if (opened != 0.) { + p.restore(); + } + } + p.setOpacity(1.); +} + +void TranscribeButton::setOpened(bool opened, Fn update) { + if (_opened == opened) { + return; + } + _opened = opened; + _openedAnimation.start( + std::move(update), + _opened ? 0. : 1., + _opened ? 1. : 0., + st::fadeWrapDuration); } ClickHandlerPtr TranscribeButton::link() { diff --git a/Telegram/SourceFiles/history/view/history_view_transcribe_button.h b/Telegram/SourceFiles/history/view/history_view_transcribe_button.h index de506cde00..69ee34413e 100644 --- a/Telegram/SourceFiles/history/view/history_view_transcribe_button.h +++ b/Telegram/SourceFiles/history/view/history_view_transcribe_button.h @@ -7,8 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "ui/effects/animations.h" + namespace Ui { struct ChatPaintContext; +class InfiniteRadialAnimation; } // namespace Ui namespace HistoryView { @@ -18,9 +21,12 @@ using PaintContext = Ui::ChatPaintContext; class TranscribeButton final { public: explicit TranscribeButton(not_null item); + ~TranscribeButton(); [[nodiscard]] QSize size() const; + void setOpened(bool opened, Fn update); + void setLoading(bool loading, Fn update); void paint(QPainter &p, int x, int y, const PaintContext &context); [[nodiscard]] ClickHandlerPtr link(); @@ -28,10 +34,12 @@ public: private: const not_null _item; + mutable std::unique_ptr _animation; ClickHandlerPtr _link; QString _text; - bool _loaded = false; + Ui::Animations::Simple _openedAnimation; bool _loading = false; + bool _opened = false; }; diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 5181676fd9..ec8e9b6e6f 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/image/image.h" #include "ui/text/format_values.h" #include "ui/text/format_song_document_name.h" +#include "ui/text/text_utilities.h" #include "ui/chat/message_bubble.h" #include "ui/chat/chat_style.h" #include "ui/cached_round_corners.h" @@ -105,6 +106,7 @@ void PaintWaveform( const auto maxDelta = st::msgWaveformMax - st::msgWaveformMin; const auto &bottom = st::msgWaveformMax; p.setPen(Qt::NoPen); + auto hq = PainterHighQualityEnabler(p); for (auto i = 0, barLeft = 0, sum = 0, maxValue = 0; i < wfSize; ++i) { const auto value = wf ? wf->at(i) : 0; if (sum + barCount < wfSize) { @@ -120,16 +122,20 @@ void PaintWaveform( const auto barValue = ((maxValue * maxDelta) + (barNormValue / 2)) / barNormValue; const auto barHeight = st::msgWaveformMin + barValue; - const auto barTop = bottom - barValue; + const auto barTop = st::lineWidth + (st::msgWaveformMax - barValue) / 2.; if ((barLeft < activeWidth) && (barLeft + barWidth > activeWidth)) { const auto leftWidth = activeWidth - barLeft; const auto rightWidth = barWidth - leftWidth; - p.fillRect(barLeft, barTop, leftWidth, barHeight, active); - p.fillRect(activeWidth, barTop, rightWidth, barHeight, inactive); + p.fillRect( + QRectF(barLeft, barTop, leftWidth, barHeight), + active); + p.fillRect( + QRectF(activeWidth, barTop, rightWidth, barHeight), + inactive); } else { const auto &color = (barLeft >= activeWidth) ? inactive : active; - p.fillRect(barLeft, barTop, barWidth, barHeight, color); + p.fillRect(QRectF(barLeft, barTop, barWidth, barHeight), color); } barLeft += barWidth + st::msgWaveformSkip; @@ -244,22 +250,26 @@ QSize Document::countOptimalSize() { } const auto &entry = session->api().transcribes().entry( _realParent); - auto text = entry.requestId - ? "Transcribing..." + const auto update = [=] { repaint(); }; + voice->transcribe->setLoading( + entry.shown && (entry.requestId || entry.pending), + update); + auto text = (entry.requestId || !entry.shown) + ? TextWithEntities() : entry.failed - ? "Transcribing Failed." - : entry.shown - ? ((entry.pending ? "Still Transcribing...\n" : "") - + entry.result) - : QString(); - if (text.isEmpty()) { + ? Ui::Text::Italic(tr::lng_attach_failed(tr::now)) + : TextWithEntities{ entry.result }; + voice->transcribe->setOpened(!text.empty(), update); + if (text.empty()) { 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); + voice->transcribeText.setMarkedText( + st::messageTextStyle, + text); hasTranscribe = true; } } @@ -599,10 +609,7 @@ void Document::draw( 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(); + const auto y = st.padding.top() - topMinus; voice->transcribe->paint(p, x, y, context); } p.save(); @@ -837,10 +844,7 @@ TextState Document::textState( 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(); + const auto y = st.padding.top() - topMinus; if (QRect(QPoint(x, y), size).contains(point)) { result.link = voice->transcribe->link(); return result; diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index b623141ca1..5e766f47b5 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -652,11 +652,20 @@ msgVideoSize: size(320px, 240px); msgWaveformBar: 2px; msgWaveformSkip: 1px; -msgWaveformMin: 2px; -msgWaveformMax: 20px; +msgWaveformMin: 3px; +msgWaveformMax: 17px; historyTranscribeSkip: 10px; -historyTranscribeSize: 24px; +historyTranscribeSize: size(28px, 22px); +historyTranscribeRadius: 4px; +historyTranscribeInIcon: icon {{ "chat/voice_to_text", msgFileInBg }}; +historyTranscribeInIconSelected: icon {{ "chat/voice_to_text", msgFileInBgSelected }}; +historyTranscribeOutIcon: icon {{ "chat/voice_to_text", msgFileOutBg }}; +historyTranscribeOutIconSelected: icon {{ "chat/voice_to_text", msgFileOutBgSelected }}; +historyTranscribeInHide: icon {{ "chat/voice_to_text_collapse", msgFileInBg }}; +historyTranscribeInHideSelected: icon {{ "chat/voice_to_text_collapse", msgFileInBgSelected }}; +historyTranscribeOutHide: icon {{ "chat/voice_to_text_collapse", msgFileOutBg }}; +historyTranscribeOutHideSelected: icon {{ "chat/voice_to_text_collapse", msgFileOutBgSelected }}; historyVideoMessageMute: icon {{ "volume_mute", historyFileThumbIconFg }}; historyVideoMessageMuteSelected: icon {{ "volume_mute", historyFileThumbIconFgSelected }}; diff --git a/Telegram/SourceFiles/ui/chat/chat_style.cpp b/Telegram/SourceFiles/ui/chat/chat_style.cpp index 5c2a9c2706..2328f2182d 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.cpp +++ b/Telegram/SourceFiles/ui/chat/chat_style.cpp @@ -398,6 +398,18 @@ ChatStyle::ChatStyle() { st::historyPollInChoiceRightSelected, st::historyPollOutChoiceRight, st::historyPollOutChoiceRightSelected); + make( + &MessageStyle::historyTranscribeIcon, + st::historyTranscribeInIcon, + st::historyTranscribeInIconSelected, + st::historyTranscribeOutIcon, + st::historyTranscribeOutIconSelected); + make( + &MessageStyle::historyTranscribeHide, + st::historyTranscribeInHide, + st::historyTranscribeInHideSelected, + st::historyTranscribeOutHide, + st::historyTranscribeOutHideSelected); make( &MessageImageStyle::msgDateImgBg, st::msgDateImgBg, diff --git a/Telegram/SourceFiles/ui/chat/chat_style.h b/Telegram/SourceFiles/ui/chat/chat_style.h index e9e1765427..6a1f34feeb 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.h +++ b/Telegram/SourceFiles/ui/chat/chat_style.h @@ -70,6 +70,9 @@ struct MessageStyle { style::icon historyQuizExplain = { Qt::Uninitialized }; style::icon historyPollChosen = { Qt::Uninitialized }; style::icon historyPollChoiceRight = { Qt::Uninitialized }; + style::icon historyTranscribeIcon = { Qt::Uninitialized }; + style::icon historyTranscribeHide = { Qt::Uninitialized }; + }; struct MessageImageStyle {