mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-06 23:24:01 +02:00
Improve emoji animation.
This commit is contained in:
parent
29d87f692a
commit
70378bfac8
6 changed files with 158 additions and 32 deletions
|
@ -4969,6 +4969,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_confcall_sure_remove" = "Remove {user} from the call?";
|
||||
"lng_confcall_e2e_badge" = "End-to-End Encrypted";
|
||||
"lng_confcall_e2e_badge_small" = "E2E Encrypted";
|
||||
"lng_confcall_e2e_about" = "These four emoji represent the call's encryption key. They must match for all participants and change when someone joins or leaves.";
|
||||
|
||||
"lng_no_mic_permission" = "Telegram needs microphone access so that you can make calls and record voice messages.";
|
||||
|
||||
|
|
|
@ -1680,3 +1680,7 @@ confcallFingerprintText: FlatLabel(defaultFlatLabel) {
|
|||
}
|
||||
}
|
||||
confcallFingerprintSkip: 2px;
|
||||
confcallFingerprintTooltipLabel: defaultImportantTooltipLabel;
|
||||
confcallFingerprintTooltip: defaultImportantTooltip;
|
||||
confcallFingerprintTooltipSkip: 12px;
|
||||
confcallFingerprintTooltipMaxWidth: 220px;
|
||||
|
|
|
@ -12,20 +12,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "calls/calls_signal_bars.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "data/data_user.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/tooltip.h"
|
||||
#include "ui/abstract_button.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "styles/style_calls.h"
|
||||
|
||||
namespace Calls {
|
||||
namespace {
|
||||
|
||||
constexpr auto kTooltipShowTimeoutMs = crl::time(1000);
|
||||
constexpr auto kCarouselOneDuration = crl::time(1000);// crl::time(100);
|
||||
constexpr auto kStartTimeShift = crl::time(500);// crl::time(50);
|
||||
constexpr auto kCarouselOneDuration = crl::time(100);
|
||||
constexpr auto kStartTimeShift = crl::time(50);
|
||||
constexpr auto kEmojiInFingerprint = 4;
|
||||
constexpr auto kEmojiInCarousel = 10;
|
||||
|
||||
|
@ -317,6 +319,7 @@ FingerprintBadge SetupFingerprintBadge(
|
|||
};
|
||||
const auto state = on.make_state<State>();
|
||||
|
||||
state->data.speed = 1. / kCarouselOneDuration;
|
||||
state->update = [=](crl::time now) {
|
||||
// speed-up-duration = 2 * one / speed.
|
||||
const auto one = 1.;
|
||||
|
@ -546,13 +549,112 @@ FingerprintBadge SetupFingerprintBadge(
|
|||
return { .state = &state->data, .repaints = state->repaints.events() };
|
||||
}
|
||||
|
||||
void SetupFingerprintTooltip(not_null<Ui::RpWidget*> widget) {
|
||||
struct State {
|
||||
std::unique_ptr<Ui::ImportantTooltip> tooltip;
|
||||
Fn<void()> updateGeometry;
|
||||
Fn<void(bool)> toggleTooltip;
|
||||
};
|
||||
const auto state = widget->lifetime().make_state<State>();
|
||||
state->updateGeometry = [=] {
|
||||
if (!state->tooltip.get()) {
|
||||
return;
|
||||
}
|
||||
const auto geometry = Ui::MapFrom(
|
||||
widget->window(),
|
||||
widget,
|
||||
widget->rect());
|
||||
if (geometry.isEmpty()) {
|
||||
state->toggleTooltip(false);
|
||||
return;
|
||||
}
|
||||
const auto weak = QPointer<QWidget>(state->tooltip.get());
|
||||
const auto countPosition = [=](QSize size) {
|
||||
const auto result = geometry.bottomLeft()
|
||||
+ QPoint(
|
||||
geometry.width() / 2,
|
||||
st::confcallFingerprintTooltipSkip)
|
||||
- QPoint(size.width() / 2, 0);
|
||||
return result;
|
||||
};
|
||||
state->tooltip.get()->pointAt(
|
||||
geometry,
|
||||
RectPart::Bottom,
|
||||
countPosition);
|
||||
};
|
||||
state->toggleTooltip = [=](bool show) {
|
||||
if (const auto was = state->tooltip.release()) {
|
||||
was->toggleAnimated(false);
|
||||
}
|
||||
if (!show) {
|
||||
return;
|
||||
}
|
||||
const auto text = tr::lng_confcall_e2e_about(
|
||||
tr::now,
|
||||
Ui::Text::WithEntities);
|
||||
if (text.empty()) {
|
||||
return;
|
||||
}
|
||||
state->tooltip = std::make_unique<Ui::ImportantTooltip>(
|
||||
widget->window(),
|
||||
Ui::MakeNiceTooltipLabel(
|
||||
widget,
|
||||
rpl::single(text),
|
||||
st::confcallFingerprintTooltipMaxWidth,
|
||||
st::confcallFingerprintTooltipLabel),
|
||||
st::confcallFingerprintTooltip);
|
||||
const auto raw = state->tooltip.get();
|
||||
const auto weak = QPointer<QWidget>(raw);
|
||||
const auto destroy = [=] {
|
||||
delete weak.data();
|
||||
};
|
||||
raw->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
raw->setHiddenCallback(destroy);
|
||||
state->updateGeometry();
|
||||
raw->toggleAnimated(true);
|
||||
};
|
||||
|
||||
widget->events() | rpl::start_with_next([=](not_null<QEvent*> e) {
|
||||
const auto type = e->type();
|
||||
if (type == QEvent::Enter) {
|
||||
state->toggleTooltip(true);
|
||||
} else if (type == QEvent::Leave) {
|
||||
state->toggleTooltip(false);
|
||||
}
|
||||
}, widget->lifetime());
|
||||
}
|
||||
|
||||
QImage MakeVerticalShadow(int height) {
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
auto result = QImage(
|
||||
QSize(1, height) * ratio,
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
result.setDevicePixelRatio(ratio);
|
||||
auto p = QPainter(&result);
|
||||
auto g = QLinearGradient(0, 0, 0, height);
|
||||
auto color = st::groupCallMembersBg->c;
|
||||
auto trans = color;
|
||||
trans.setAlpha(0);
|
||||
g.setStops({
|
||||
{ 0.0, color },
|
||||
{ 0.4, trans },
|
||||
{ 0.6, trans },
|
||||
{ 1.0, color },
|
||||
});
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
p.fillRect(0, 0, 1, height, g);
|
||||
p.end();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void SetupFingerprintBadgeWidget(
|
||||
not_null<Ui::RpWidget*> widget,
|
||||
not_null<const FingerprintBadgeState*> state,
|
||||
rpl::producer<> repaints) {
|
||||
auto &lifetime = widget->lifetime();
|
||||
|
||||
const auto button = Ui::CreateChild<Ui::AbstractButton>(widget);
|
||||
const auto button = Ui::CreateChild<Ui::RpWidget>(widget);
|
||||
button->show();
|
||||
|
||||
const auto label = Ui::CreateChild<Ui::FlatLabel>(
|
||||
|
@ -633,12 +735,19 @@ void SetupFingerprintBadgeWidget(
|
|||
st::confcallFingerprintTextMargins);
|
||||
const auto count = int(state->entries.size());
|
||||
cache->entries.resize(count);
|
||||
cache->shadow = MakeVerticalShadow(outer.height());
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
PaintFingerprintEntry(
|
||||
p,
|
||||
state->entries[i],
|
||||
cache->entries[i],
|
||||
esize);
|
||||
const auto &entry = state->entries[i];
|
||||
auto &cached = cache->entries[i];
|
||||
const auto shadowed = entry.speed / state->speed;
|
||||
PaintFingerprintEntry(p, entry, cached, esize);
|
||||
if (shadowed > 0.) {
|
||||
p.setOpacity(shadowed);
|
||||
p.drawImage(
|
||||
QRect(0, -st::confcallFingerprintMargins.top(), size, outer.height()),
|
||||
cache->shadow);
|
||||
p.setOpacity(1.);
|
||||
}
|
||||
if (i + 1 == count / 2) {
|
||||
p.translate(size + textOuter.width(), 0);
|
||||
} else {
|
||||
|
@ -650,6 +759,8 @@ void SetupFingerprintBadgeWidget(
|
|||
std::move(repaints) | rpl::start_with_next([=] {
|
||||
button->update();
|
||||
}, lifetime);
|
||||
|
||||
SetupFingerprintTooltip(button);
|
||||
}
|
||||
|
||||
void PaintFingerprintEntry(
|
||||
|
|
|
@ -37,6 +37,7 @@ struct FingerprintBadgeState {
|
|||
int added = 0;
|
||||
};
|
||||
std::vector<Entry> entries;
|
||||
float64 speed = 1.;
|
||||
};
|
||||
struct FingerprintBadge {
|
||||
not_null<const FingerprintBadgeState*> state;
|
||||
|
@ -60,6 +61,7 @@ struct FingerprintBadgeCache {
|
|||
std::vector<Emoji> emoji;
|
||||
};
|
||||
std::vector<Entry> entries;
|
||||
QImage shadow;
|
||||
};
|
||||
void PaintFingerprintEntry(
|
||||
QPainter &p,
|
||||
|
|
|
@ -115,6 +115,7 @@ private:
|
|||
|
||||
struct PrioritizedSelector {
|
||||
object_ptr<Ui::RpWidget> content = { nullptr };
|
||||
Fn<void()> init;
|
||||
Fn<bool(int, int, int)> overrideKey;
|
||||
Fn<void(PeerListRowId)> deselect;
|
||||
Fn<void()> activate;
|
||||
|
@ -320,7 +321,7 @@ void ConfInviteRow::elementsPaint(
|
|||
[[nodiscard]] PrioritizedSelector PrioritizedInviteSelector(
|
||||
const ConfInviteStyles &st,
|
||||
std::vector<not_null<UserData*>> users,
|
||||
Fn<bool(not_null<PeerListRow*>, bool)> toggleGetChecked,
|
||||
Fn<bool(not_null<PeerListRow*>, bool, anim::type)> toggleGetChecked,
|
||||
Fn<bool()> lastSelectWithVideo,
|
||||
Fn<void(bool)> setLastSelectWithVideo) {
|
||||
class PrioritizedController final : public PeerListController {
|
||||
|
@ -328,7 +329,10 @@ void ConfInviteRow::elementsPaint(
|
|||
PrioritizedController(
|
||||
const ConfInviteStyles &st,
|
||||
std::vector<not_null<UserData*>> users,
|
||||
Fn<bool(not_null<PeerListRow*>, bool)> toggleGetChecked,
|
||||
Fn<bool(
|
||||
not_null<PeerListRow*>,
|
||||
bool,
|
||||
anim::type)> toggleGetChecked,
|
||||
Fn<bool()> lastSelectWithVideo,
|
||||
Fn<void(bool)> setLastSelectWithVideo)
|
||||
: _st(st)
|
||||
|
@ -368,7 +372,7 @@ void ConfInviteRow::elementsPaint(
|
|||
void toggleRowSelected(not_null<PeerListRow*> row, bool video) {
|
||||
delegate()->peerListSetRowChecked(
|
||||
row,
|
||||
_toggleGetChecked(row, video));
|
||||
_toggleGetChecked(row, video, anim::type::normal));
|
||||
}
|
||||
|
||||
Main::Session &session() const override {
|
||||
|
@ -382,7 +386,7 @@ void ConfInviteRow::elementsPaint(
|
|||
private:
|
||||
const ConfInviteStyles &_st;
|
||||
std::vector<not_null<UserData*>> _users;
|
||||
Fn<bool(not_null<PeerListRow*>, bool)> _toggleGetChecked;
|
||||
Fn<bool(not_null<PeerListRow*>, bool, anim::type)> _toggleGetChecked;
|
||||
Fn<bool()> _lastSelectWithVideo;
|
||||
Fn<void(bool)> _setLastSelectWithVideo;
|
||||
|
||||
|
@ -448,8 +452,19 @@ void ConfInviteRow::elementsPaint(
|
|||
}
|
||||
};
|
||||
|
||||
const auto init = [=] {
|
||||
for (const auto &user : users) {
|
||||
if (const auto row = delegate->peerListFindRow(user->id.value)) {
|
||||
delegate->peerListSetRowChecked(
|
||||
row,
|
||||
toggleGetChecked(row, false, anim::type::instant));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
.content = std::move(result),
|
||||
.init = init,
|
||||
.overrideKey = overrideKey,
|
||||
.deselect = deselect,
|
||||
.activate = activate,
|
||||
|
@ -608,12 +623,15 @@ void ConfInviteController::prepareViewHook() {
|
|||
}
|
||||
|
||||
void ConfInviteController::addPriorityInvites() {
|
||||
const auto toggleGetChecked = [=](not_null<PeerListRow*> row, bool video) {
|
||||
const auto toggleGetChecked = [=](
|
||||
not_null<PeerListRow*> row,
|
||||
bool video,
|
||||
anim::type animated) {
|
||||
const auto result = toggleRowGetChecked(row, video);
|
||||
delegate()->peerListSetForeignRowChecked(
|
||||
row,
|
||||
result,
|
||||
anim::type::normal);
|
||||
animated);
|
||||
|
||||
_hasSelected = (delegate()->peerListSelectedRowsCount() > 0);
|
||||
|
||||
|
@ -630,6 +648,13 @@ void ConfInviteController::addPriorityInvites() {
|
|||
scrollTo
|
||||
) | rpl::start_to_stream(_prioritizeScrollRequests, lifetime());
|
||||
}
|
||||
if (const auto onstack = _prioritizeRows.init) {
|
||||
onstack();
|
||||
|
||||
// Force finishing in instant adding checked rows bunch.
|
||||
delegate()->peerListAddSelectedPeers(
|
||||
std::vector<not_null<PeerData*>>());
|
||||
}
|
||||
delegate()->peerListSetAboveWidget(std::move(_prioritizeRows.content));
|
||||
}
|
||||
|
||||
|
|
|
@ -77,23 +77,6 @@ constexpr auto kControlsBackgroundOpacity = 0.8;
|
|||
constexpr auto kOverrideActiveColorBgAlpha = 172;
|
||||
constexpr auto kHideControlsTimeout = 5 * crl::time(1000);
|
||||
|
||||
[[nodiscard]] QString ComposeTitle(const QByteArray &hash) {
|
||||
auto result = tr::lng_confcall_join_title(tr::now);
|
||||
if (hash.size() >= 32) {
|
||||
const auto fp = bytes::make_span(hash).subspan(0, 32);
|
||||
const auto emoji = Calls::ComputeEmojiFingerprint(fp);
|
||||
result += QString::fromUtf8(" \xc2\xb7 ");
|
||||
const auto base = result.size();
|
||||
for (const auto &single : emoji) {
|
||||
result += single->text();
|
||||
}
|
||||
MTP_LOG(0, ("Got Emoji: %1.").arg(result.mid(base)));
|
||||
} else {
|
||||
MTP_LOG(0, ("Cleared Emoji."));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
void UnpinMaximized(not_null<QWidget*> widget) {
|
||||
SetWindowPos(
|
||||
|
@ -2417,7 +2400,7 @@ void Panel::updateMembersGeometry() {
|
|||
|
||||
rpl::producer<QString> Panel::titleText() {
|
||||
if (_call->conference()) {
|
||||
return _call->emojiHashValue() | rpl::map(ComposeTitle);
|
||||
return tr::lng_confcall_join_title();
|
||||
}
|
||||
return rpl::combine(
|
||||
Info::Profile::NameValue(_peer),
|
||||
|
|
Loading…
Add table
Reference in a new issue