Added animation of send action for stickers to middle of text.

This commit is contained in:
23rd 2021-08-30 20:38:11 +03:00
parent 8c17e3e578
commit 436212bb88
8 changed files with 93 additions and 9 deletions

View File

@ -405,6 +405,7 @@ public:
struct SendActionAnimationUpdate {
not_null<History*> history;
int left = 0;
int width = 0;
int height = 0;
bool textUpdated = false;

View File

@ -171,6 +171,7 @@ InnerWidget::InnerWidget(
const Data::Session::SendActionAnimationUpdate &update) {
using RowPainter = Layout::RowPainter;
const auto updateRect = RowPainter::sendActionAnimationRect(
update.left,
update.width,
update.height,
width(),

View File

@ -943,11 +943,24 @@ void RowPainter::paint(
paintCounterCallback);
}
QRect RowPainter::sendActionAnimationRect(int animationWidth, int animationHeight, int fullWidth, bool textUpdated) {
auto nameleft = st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPhotoPadding;
auto namewidth = fullWidth - nameleft - st::dialogsPadding.x();
auto texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip;
return QRect(nameleft, texttop, textUpdated ? namewidth : animationWidth, animationHeight);
QRect RowPainter::sendActionAnimationRect(
int animationLeft,
int animationWidth,
int animationHeight,
int fullWidth,
bool textUpdated) {
const auto nameleft = st::dialogsPadding.x()
+ st::dialogsPhotoSize
+ st::dialogsPhotoPadding;
const auto namewidth = fullWidth - nameleft - st::dialogsPadding.x();
const auto texttop = st::dialogsPadding.y()
+ st::msgNameFont->height
+ st::dialogsSkip;
return QRect(
nameleft + (textUpdated ? 0 : animationLeft),
texttop,
textUpdated ? namewidth : animationWidth,
animationHeight);
}
void PaintCollapsedRow(

View File

@ -39,6 +39,7 @@ public:
crl::time ms,
bool displayUnreadInfo);
static QRect sendActionAnimationRect(
int animationLeft,
int animationWidth,
int animationHeight,
int fullWidth,

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "main/main_session.h"
#include "history/history.h"
#include "lang/lang_instance.h" // Instance::supportChoosingStickerReplacement
#include "lang/lang_keys.h"
#include "ui/effects/animations.h"
#include "ui/text/text_options.h"
@ -39,6 +40,7 @@ constexpr auto kStatusShowClientsideSpeaking = 6 * crl::time(1000);
SendActionPainter::SendActionPainter(not_null<History*> history)
: _history(history)
, _weak(&_history->session())
, _st(st::dialogsTextStyle)
, _sendActionText(st::dialogsTextWidthMin) {
}
@ -130,16 +132,29 @@ bool SendActionPainter::paint(
style::color color,
crl::time ms) {
if (_sendActionAnimation) {
const auto animationWidth = _sendActionAnimation.width();
const auto extraAnimationWidth = _animationLeft
? animationWidth * 2
: 0;
const auto left =
(availableWidth < _animationLeft + extraAnimationWidth)
? 0
: _animationLeft;
_sendActionAnimation.paint(
p,
color,
x,
left + x,
y + st::normalFont->ascent,
outerWidth,
ms);
auto animationWidth = _sendActionAnimation.width();
x += animationWidth;
availableWidth -= animationWidth;
// availableWidth should be the same
// if an animation is in the middle of text.
if (!left) {
x += animationWidth;
availableWidth -= _animationLeft
? extraAnimationWidth
: animationWidth;
}
p.setPen(color);
_sendActionText.drawElided(p, x, y, availableWidth);
return true;
@ -270,6 +285,30 @@ bool SendActionPainter::updateNeedsAnimating(crl::time now, bool force) {
_history->peer->isUser() ? QString() : user->firstName);
if (!newTypingString.isEmpty()) {
_sendActionAnimation.start(action.type);
// Add an animation to the middle of text.
using namespace Lang;
if (GetInstance().supportChoosingStickerReplacement()
&& (action.type == Type::ChooseSticker)) {
const auto index = newTypingString.lastIndexOf(
Lang::kChoosingStickerReplacement.utf8());
_animationLeft = (index == -1)
? 0
: _st.font->width(newTypingString, 0, index);
if (!_spacesCount) {
_spacesCount = std::ceil(
_sendActionAnimation.width()
/ _st.font->spacew);
}
newTypingString = newTypingString.replace(
Lang::kChoosingStickerReplacement.utf8(),
QString().fill(' ', _spacesCount));
} else {
_animationLeft = 0;
}
break;
}
}
@ -327,6 +366,7 @@ bool SendActionPainter::updateNeedsAnimating(crl::time now, bool force) {
|| (sendActionResult && !anim::Disabled())) {
_history->peer->owner().updateSendActionAnimation({
_history,
_animationLeft,
_sendActionAnimation.width(),
st::normalFont->height,
(force || sendActionChanged)

View File

@ -54,6 +54,7 @@ public:
private:
const not_null<History*> _history;
const base::weak_ptr<Main::Session> _weak;
const style::TextStyle &_st;
base::flat_map<not_null<UserData*>, crl::time> _typing;
base::flat_map<not_null<UserData*>, crl::time> _speaking;
base::flat_map<not_null<UserData*>, Api::SendProgress> _sendActions;
@ -62,6 +63,9 @@ private:
Ui::SendActionAnimation _sendActionAnimation;
Ui::SendActionAnimation _speakingAnimation;
int _animationLeft = 0;
int _spacesCount = 0;
};
} // namespace HistoryView

View File

@ -303,6 +303,7 @@ void Instance::reset(const Language &data) {
_values[i] = GetOriginalValue(ushort(i));
}
ranges::fill(_nonDefaultSet, 0);
updateSupportChoosingStickerReplacement();
_idChanges.fire_copy(_id);
}
@ -548,6 +549,7 @@ void Instance::fillFromSerialized(
applyValue(nonDefaultStrings[i], nonDefaultStrings[i + 1]);
}
updatePluralRules();
updateSupportChoosingStickerReplacement();
_idChanges.fire_copy(_id);
}
@ -572,6 +574,7 @@ void Instance::fillFromCustomContent(
_pluralId = PluralCodeForCustom(absolutePath, relativePath);
_name = _nativeName = QString();
loadFromCustomContent(absolutePath, relativePath, content);
updateSupportChoosingStickerReplacement();
_idChanges.fire_copy(_id);
}
@ -602,6 +605,20 @@ bool Instance::loadFromCustomFile(const QString &filePath) {
return false;
}
void Instance::updateSupportChoosingStickerReplacement() {
// A language changing in the runtime is not supported.
const auto phrase = tr::lng_send_action_choose_sticker(tr::now);
const auto first = phrase.indexOf(kChoosingStickerReplacement.utf8());
const auto last = phrase.lastIndexOf(kChoosingStickerReplacement.utf8());
_supportChoosingStickerReplacement = (first == last)
? (first != -1)
: false;
}
bool Instance::supportChoosingStickerReplacement() const {
return _supportChoosingStickerReplacement;
}
// SetCallback takes two QByteArrays: key, value.
// It is called for all key-value pairs in string.
// ResetCallback takes one QByteArray: key.

View File

@ -13,6 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Lang {
inline constexpr auto kChoosingStickerReplacement = "oo"_cs;
struct Language {
QString id;
QString pluralId;
@ -74,6 +76,8 @@ public:
QByteArray serialize() const;
void fillFromSerialized(const QByteArray &data, int dataAppVersion);
bool supportChoosingStickerReplacement() const;
void applyDifference(
Pack pack,
const MTPDlangPackDifference &difference);
@ -120,6 +124,7 @@ private:
const QString &relativePath,
const QByteArray &content);
void updatePluralRules();
void updateSupportChoosingStickerReplacement();
Instance *_derived = nullptr;
@ -132,6 +137,8 @@ private:
int _version = 0;
rpl::event_stream<> _updated;
bool _supportChoosingStickerReplacement;
mutable QString _systemLanguage;
std::vector<QString> _values;