mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Implement nice Cocoon about box.
This commit is contained in:
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
@@ -4971,6 +4971,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
"lng_translate_settings" = "Settings";
|
"lng_translate_settings" = "Settings";
|
||||||
"lng_translate_undo" = "Undo";
|
"lng_translate_undo" = "Undo";
|
||||||
|
|
||||||
|
"lng_translate_cocoon_menu" = "Translations are powered by\n**{emoji} Cocoon**. {link}";
|
||||||
|
"lng_translate_cocoon_link" = "How does it work?";
|
||||||
|
"lng_translate_cocoon_title" = "Cocoon";
|
||||||
|
"lng_translate_cocoon_subtitle" = "**Cocoon** ({text}) handles AI tasks **safely** and **efficiently**.";
|
||||||
|
"lng_translate_cocoon_explain" = "**Co**nfidential **Co**mpute **O**pen **N**etwork";
|
||||||
|
"lng_translate_cocoon_private_title" = "Private";
|
||||||
|
"lng_translate_cocoon_private_text" = "No third party can access any data, such as translations, inside {mention}.";
|
||||||
|
"lng_translate_cocoon_private_mention" = "@cocoon";
|
||||||
|
"lng_translate_cocoon_efficient_title" = "Efficient";
|
||||||
|
"lng_translate_cocoon_efficient_text" = "Cocoon has allowed Telegram to reduce translation costs by 6x.";
|
||||||
|
"lng_translate_cocoon_everyone_title" = "For Everyone";
|
||||||
|
"lng_translate_cocoon_everyone_text" = "Any developer can use Cocoon for AI features. Learn more at {domain}.";
|
||||||
|
"lng_translate_cocoon_everyone_domain" = "cocoon.org";
|
||||||
|
"lng_translate_cocoon_text" = "Want to integrate Cocoon into your projects?\nReach out at {link}";
|
||||||
|
"lng_translate_cocoon_text_link" = "t.me/cocoon?direct";
|
||||||
|
"lng_translate_cocoon_done" = "Understood";
|
||||||
|
|
||||||
"lng_downloads_section" = "Downloads";
|
"lng_downloads_section" = "Downloads";
|
||||||
"lng_downloads_view_in_chat" = "View in chat";
|
"lng_downloads_view_in_chat" = "View in chat";
|
||||||
"lng_downloads_view_in_section" = "View in downloads";
|
"lng_downloads_view_in_section" = "View in downloads";
|
||||||
|
|||||||
@@ -52,6 +52,7 @@
|
|||||||
<file alias="show_or_premium_readtime.tgs">../../animations/show_or_premium_readtime.tgs</file>
|
<file alias="show_or_premium_readtime.tgs">../../animations/show_or_premium_readtime.tgs</file>
|
||||||
<file alias="passkeys.tgs">../../animations/passkeys.tgs</file>
|
<file alias="passkeys.tgs">../../animations/passkeys.tgs</file>
|
||||||
<file alias="ban.tgs">../../animations/ban.tgs</file>
|
<file alias="ban.tgs">../../animations/ban.tgs</file>
|
||||||
|
<file alias="cocoon.tgs">../../animations/cocoon.tgs</file>
|
||||||
|
|
||||||
<file alias="profile_muting.tgs">../../animations/profile/profile_muting.tgs</file>
|
<file alias="profile_muting.tgs">../../animations/profile/profile_muting.tgs</file>
|
||||||
<file alias="profile_unmuting.tgs">../../animations/profile/profile_unmuting.tgs</file>
|
<file alias="profile_unmuting.tgs">../../animations/profile/profile_unmuting.tgs</file>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
<file alias="art/logo_256_no_margin.png">../../art/logo_256_no_margin.png</file>
|
<file alias="art/logo_256_no_margin.png">../../art/logo_256_no_margin.png</file>
|
||||||
<file alias="art/themeimage.jpg">../../art/themeimage.jpg</file>
|
<file alias="art/themeimage.jpg">../../art/themeimage.jpg</file>
|
||||||
<file alias="art/round_placeholder.jpg">../../art/round_placeholder.jpg</file>
|
<file alias="art/round_placeholder.jpg">../../art/round_placeholder.jpg</file>
|
||||||
|
<file alias="art/cocoon.webp">../../art/cocoon.webp</file>
|
||||||
<file alias="day-blue.tdesktop-theme">../../day-blue.tdesktop-theme</file>
|
<file alias="day-blue.tdesktop-theme">../../day-blue.tdesktop-theme</file>
|
||||||
<file alias="night.tdesktop-theme">../../night.tdesktop-theme</file>
|
<file alias="night.tdesktop-theme">../../night.tdesktop-theme</file>
|
||||||
<file alias="night-green.tdesktop-theme">../../night-green.tdesktop-theme</file>
|
<file alias="night-green.tdesktop-theme">../../night-green.tdesktop-theme</file>
|
||||||
|
|||||||
@@ -354,10 +354,37 @@ not_null<DocumentData*> GenerateLocalSticker(
|
|||||||
not_null<DocumentData*> GenerateLocalTgsSticker(
|
not_null<DocumentData*> GenerateLocalTgsSticker(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
const QString &name) {
|
const QString &name) {
|
||||||
|
const auto cache = [&] {
|
||||||
|
struct Session {
|
||||||
|
base::weak_ptr<Main::Session> session;
|
||||||
|
base::flat_map<QString, not_null<DocumentData*>> cache;
|
||||||
|
};
|
||||||
|
static auto Map = std::vector<Session>();
|
||||||
|
for (auto i = begin(Map); i != end(Map);) {
|
||||||
|
if (const auto strong = i->session.get()) {
|
||||||
|
if (strong == session) {
|
||||||
|
return &i->cache;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
} else {
|
||||||
|
i = Map.erase(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map.push_back({ .session = session });
|
||||||
|
return &Map.back().cache;
|
||||||
|
}();
|
||||||
|
|
||||||
|
const auto i = cache->find(name);
|
||||||
|
if (i != end(*cache)) {
|
||||||
|
return i->second;
|
||||||
|
}
|
||||||
|
|
||||||
const auto result = GenerateLocalSticker(
|
const auto result = GenerateLocalSticker(
|
||||||
session,
|
session,
|
||||||
u":/animations/"_q + name + u".tgs"_q);
|
u":/animations/"_q + name + u".tgs"_q);
|
||||||
|
|
||||||
|
cache->emplace(name, result);
|
||||||
|
|
||||||
Ensures(result->sticker()->isLottie());
|
Ensures(result->sticker()->isLottie());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,19 +7,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
*/
|
*/
|
||||||
#include "history/view/history_view_translate_bar.h"
|
#include "history/view/history_view_translate_bar.h"
|
||||||
|
|
||||||
|
#include "boxes/star_gift_box.h" // AddUniqueCloseButton
|
||||||
#include "boxes/translate_box.h"
|
#include "boxes/translate_box.h"
|
||||||
|
#include "chat_helpers/stickers_lottie.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "core/core_settings.h"
|
#include "core/core_settings.h"
|
||||||
|
#include "core/ui_integration.h"
|
||||||
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
|
#include "data/data_document.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
#include "settings/settings_credits_graphics.h" // CreditsEntryBoxStyleOverrides
|
||||||
|
#include "ui/controls/feature_list.h"
|
||||||
|
#include "ui/effects/ministar_particles.h"
|
||||||
#include "ui/effects/ripple_animation.h"
|
#include "ui/effects/ripple_animation.h"
|
||||||
#include "ui/boxes/choose_language_box.h" // EditSkipTranslationLanguages.
|
#include "ui/boxes/choose_language_box.h" // EditSkipTranslationLanguages.
|
||||||
#include "ui/layers/box_content.h"
|
#include "ui/layers/box_content.h"
|
||||||
|
#include "ui/layers/generic_box.h"
|
||||||
#include "ui/widgets/menu/menu_item_base.h"
|
#include "ui/widgets/menu/menu_item_base.h"
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
|
#include "ui/top_background_gradient.h"
|
||||||
|
#include "ui/widgets/menu/menu_multiline_action.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
@@ -27,6 +38,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
|
#include "styles/style_info.h" // infoStarsUnderstood
|
||||||
|
#include "styles/style_layers.h"
|
||||||
#include "styles/style_menu_icons.h"
|
#include "styles/style_menu_icons.h"
|
||||||
|
|
||||||
#include <QtGui/QtEvents>
|
#include <QtGui/QtEvents>
|
||||||
@@ -80,6 +93,247 @@ TextParseOptions MenuTextOptions = {
|
|||||||
Qt::LayoutDirectionAuto, // dir
|
Qt::LayoutDirectionAuto, // dir
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void AddCocoonBoxCover(not_null<Ui::VerticalLayout*> container) {
|
||||||
|
const auto cover = container->add(object_ptr<Ui::RpWidget>(container));
|
||||||
|
|
||||||
|
static const auto gradientEdge = QColor(0x06, 0x11, 0x29);
|
||||||
|
static const auto gradientCenter = QColor(0x09, 0x16, 0x43);
|
||||||
|
|
||||||
|
static const auto gradientLeft = QColor(0x68, 0xc9, 0xff);
|
||||||
|
static const auto gradientRight = QColor(0xcb, 0x57, 0xff);
|
||||||
|
|
||||||
|
static const auto textColor = QColor(0xb8, 0xc9, 0xef);
|
||||||
|
static const auto boldColor = QColor(0xff, 0xff, 0xff);
|
||||||
|
|
||||||
|
const auto logoTop = st::cocoonLogoTop;
|
||||||
|
const auto logoSize = st::cocoonLogoSize;
|
||||||
|
const auto ratio = style::DevicePixelRatio();
|
||||||
|
auto logo = QImage(u":/gui/art/cocoon.webp"_q).scaled(
|
||||||
|
QSize(logoSize, logoSize) * ratio,
|
||||||
|
Qt::IgnoreAspectRatio,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
|
logo.setDevicePixelRatio(ratio);
|
||||||
|
const auto titleTop = logoTop + logoSize + st::cocoonTitleTop;
|
||||||
|
const auto subtitleTop = titleTop
|
||||||
|
+ st::cocoonTitleFont->height
|
||||||
|
+ st::cocoonSubtitleTop;
|
||||||
|
|
||||||
|
const auto boldToColorized = [](QString text) {
|
||||||
|
auto result = tr::rich(text);
|
||||||
|
auto &entities = result.entities;
|
||||||
|
for (auto i = entities.begin(); i != entities.end(); ++i) {
|
||||||
|
if (i->type() == EntityType::Bold) {
|
||||||
|
i = entities.insert(
|
||||||
|
i,
|
||||||
|
EntityInText(
|
||||||
|
EntityType::Colorized,
|
||||||
|
i->offset(),
|
||||||
|
i->length()));
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
QImage gradient;
|
||||||
|
Ui::Animations::Basic animation;
|
||||||
|
std::optional<Ui::StarParticles> particles;
|
||||||
|
style::owned_color subtitleFg = style::owned_color{ textColor };
|
||||||
|
style::owned_color subtitleBoldFg = style::owned_color{ boldColor };
|
||||||
|
style::FlatLabel subtitleSt = st::cocoonSubtitle;
|
||||||
|
};
|
||||||
|
const auto state = cover->lifetime().make_state<State>();
|
||||||
|
state->subtitleSt.textFg = state->subtitleFg.color();
|
||||||
|
state->subtitleSt.palette.linkFg = state->subtitleBoldFg.color();
|
||||||
|
state->animation.init([=] {
|
||||||
|
cover->update();
|
||||||
|
if (anim::Disabled()) {
|
||||||
|
state->animation.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
constexpr auto kParticlesCount = 50;
|
||||||
|
state->particles.emplace(
|
||||||
|
Ui::StarParticles::Type::RadialInside,
|
||||||
|
kParticlesCount,
|
||||||
|
st::cocoonLogoSize / 12);
|
||||||
|
state->particles->setSpeed(0.05);
|
||||||
|
auto particleColors = std::vector<QColor>();
|
||||||
|
constexpr auto kParticleColors = 12;
|
||||||
|
particleColors.reserve(kParticleColors);
|
||||||
|
for (auto i = 0; i != kParticleColors; ++i) {
|
||||||
|
particleColors.push_back(anim::color(
|
||||||
|
gradientLeft,
|
||||||
|
gradientRight,
|
||||||
|
float64(i) / (kParticleColors - 1)));
|
||||||
|
}
|
||||||
|
state->particles->setColors(std::move(particleColors));
|
||||||
|
|
||||||
|
const auto subtitle = CreateChild<Ui::FlatLabel>(
|
||||||
|
cover,
|
||||||
|
tr::lng_translate_cocoon_subtitle(
|
||||||
|
lt_text,
|
||||||
|
tr::lng_translate_cocoon_explain(boldToColorized),
|
||||||
|
tr::rich),
|
||||||
|
state->subtitleSt);
|
||||||
|
subtitle->setTryMakeSimilarLines(true);
|
||||||
|
|
||||||
|
cover->widthValue() | rpl::on_next([=](int width) {
|
||||||
|
const auto available = width
|
||||||
|
- st::boxRowPadding.left()
|
||||||
|
- st::boxRowPadding.right();
|
||||||
|
subtitle->resizeToWidth(available);
|
||||||
|
subtitle->moveToLeft(st::boxRowPadding.left(), subtitleTop);
|
||||||
|
|
||||||
|
const auto bottom = st::cocoonSubtitleBottom;
|
||||||
|
cover->resize(width, subtitle->y() + subtitle->height() + bottom);
|
||||||
|
}, cover->lifetime());
|
||||||
|
|
||||||
|
cover->paintRequest() | rpl::on_next([=] {
|
||||||
|
auto p = Painter(cover);
|
||||||
|
|
||||||
|
const auto width = cover->width();
|
||||||
|
const auto ratio = style::DevicePixelRatio();
|
||||||
|
if (state->gradient.size() != cover->size() * ratio) {
|
||||||
|
state->gradient = Ui::CreateTopBgGradient(
|
||||||
|
cover->size(),
|
||||||
|
gradientCenter,
|
||||||
|
gradientEdge);
|
||||||
|
|
||||||
|
auto font = st::cocoonTitleFont->f;
|
||||||
|
font.setWeight(QFont::Bold);
|
||||||
|
auto metrics = QFontMetrics(font);
|
||||||
|
|
||||||
|
const auto text = tr::lng_translate_cocoon_title(tr::now);
|
||||||
|
const auto textw = metrics.width(text);
|
||||||
|
const auto left = (width - textw) / 2;
|
||||||
|
|
||||||
|
auto q = QPainter(&state->gradient);
|
||||||
|
auto hq = PainterHighQualityEnabler(q);
|
||||||
|
|
||||||
|
auto gradient = QLinearGradient(left, 0, left + textw, 0);
|
||||||
|
gradient.setStops({
|
||||||
|
{ 0., gradientLeft },
|
||||||
|
{ 1., gradientRight },
|
||||||
|
});
|
||||||
|
auto pen = QPen(QBrush(gradient), 1.);
|
||||||
|
q.setPen(pen);
|
||||||
|
q.setFont(font);
|
||||||
|
q.setBrush(Qt::NoBrush);
|
||||||
|
|
||||||
|
q.drawText(left, titleTop + metrics.ascent(), text);
|
||||||
|
}
|
||||||
|
p.drawImage(0, 0, state->gradient);
|
||||||
|
|
||||||
|
const auto logoRect = QRect(
|
||||||
|
(width - logoSize) / 2,
|
||||||
|
logoTop,
|
||||||
|
logoSize,
|
||||||
|
logoSize);
|
||||||
|
const auto paddingAdd = int(base::SafeRound(logoTop * 1.2));
|
||||||
|
const auto particlesRect = logoRect.marginsAdded(
|
||||||
|
{ paddingAdd, paddingAdd, paddingAdd, paddingAdd });
|
||||||
|
|
||||||
|
state->particles->paint(p, particlesRect, crl::now());
|
||||||
|
if (!anim::Disabled() && !state->animation.animating()) {
|
||||||
|
state->animation.start();
|
||||||
|
}
|
||||||
|
p.drawImage(logoRect, logo);
|
||||||
|
}, cover->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CocoonLinkInfo {
|
||||||
|
QString text;
|
||||||
|
QString link;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] CocoonLinkInfo CocoonMention() {
|
||||||
|
const auto mention = tr::lng_translate_cocoon_private_mention(tr::now);
|
||||||
|
const auto username = QString(mention).replace('@', QString());
|
||||||
|
const auto link = u"tg://resolve?domain="_q + username;
|
||||||
|
return { mention, link };
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] CocoonLinkInfo CocoonDomain() {
|
||||||
|
const auto domain = tr::lng_translate_cocoon_everyone_domain(tr::now);
|
||||||
|
const auto link = u"https://"_q + domain;
|
||||||
|
return { domain, link };
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] CocoonLinkInfo CocoonDirect() {
|
||||||
|
const auto text = tr::lng_translate_cocoon_text_link(tr::now);
|
||||||
|
const auto link = u"https://"_q + text;
|
||||||
|
return { text, link };
|
||||||
|
}
|
||||||
|
|
||||||
|
void AboutCocoonBox(not_null<Ui::GenericBox*> box) {
|
||||||
|
box->setWidth(st::boxWideWidth);
|
||||||
|
box->setStyle(st::stakeBox);
|
||||||
|
box->setNoContentMargin(true);
|
||||||
|
|
||||||
|
const auto container = box->verticalLayout();
|
||||||
|
AddCocoonBoxCover(container);
|
||||||
|
|
||||||
|
AddUniqueCloseButton(box, {});
|
||||||
|
|
||||||
|
const auto mention = CocoonMention();
|
||||||
|
const auto domain = CocoonDomain();
|
||||||
|
const auto direct = CocoonDirect();
|
||||||
|
const auto features = std::vector<Ui::FeatureListEntry>{
|
||||||
|
{
|
||||||
|
st::menuIconLock,
|
||||||
|
tr::lng_translate_cocoon_private_title(tr::now),
|
||||||
|
tr::lng_translate_cocoon_private_text(
|
||||||
|
tr::now,
|
||||||
|
lt_mention,
|
||||||
|
tr::link(mention.text, mention.link),
|
||||||
|
tr::rich),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
st::menuIconStats,
|
||||||
|
tr::lng_translate_cocoon_efficient_title(tr::now),
|
||||||
|
tr::lng_translate_cocoon_efficient_text(tr::now, tr::rich),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
st::menuIconGiftPremium,
|
||||||
|
tr::lng_translate_cocoon_everyone_title(tr::now),
|
||||||
|
tr::lng_translate_cocoon_everyone_text(
|
||||||
|
tr::now,
|
||||||
|
lt_domain,
|
||||||
|
tr::link(domain.text, domain.link),
|
||||||
|
tr::rich),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
auto margin = QMargins(0, st::defaultVerticalListSkip, 0, 0);
|
||||||
|
for (const auto &feature : features) {
|
||||||
|
box->addRow(
|
||||||
|
MakeFeatureListEntry(box, feature),
|
||||||
|
st::boxRowPadding + margin);
|
||||||
|
margin = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
box->addRow(
|
||||||
|
object_ptr<Ui::PlainShadow>(box),
|
||||||
|
st::cocoonJoinSeparatorPadding);
|
||||||
|
|
||||||
|
box->addRow(
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
box,
|
||||||
|
tr::lng_translate_cocoon_text(
|
||||||
|
lt_link,
|
||||||
|
rpl::single(tr::link(direct.text, direct.link)),
|
||||||
|
tr::rich),
|
||||||
|
st::cocoonJoinLabel),
|
||||||
|
style::al_top);
|
||||||
|
|
||||||
|
box->addButton(rpl::single(QString()), [=] {
|
||||||
|
box->closeBox();
|
||||||
|
})->setText(rpl::single(Ui::Text::IconEmoji(
|
||||||
|
&st::infoStarsUnderstood
|
||||||
|
).append(' ').append(tr::lng_translate_cocoon_done(tr::now))));
|
||||||
|
}
|
||||||
|
|
||||||
TwoTextAction::TwoTextAction(
|
TwoTextAction::TwoTextAction(
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
const style::Menu &st,
|
const style::Menu &st,
|
||||||
@@ -476,6 +730,36 @@ void TranslateBar::showMenu(base::unique_qptr<Ui::PopupMenu> menu) {
|
|||||||
tr::lng_translate_menu_hide(tr::now),
|
tr::lng_translate_menu_hide(tr::now),
|
||||||
hideBar,
|
hideBar,
|
||||||
&st::menuIconCancel);
|
&st::menuIconCancel);
|
||||||
|
_menu->addSeparator();
|
||||||
|
|
||||||
|
const auto cocoon = ChatHelpers::GenerateLocalTgsSticker(
|
||||||
|
&_history->session(),
|
||||||
|
u"cocoon"_q);
|
||||||
|
cocoon->overrideEmojiUsesTextColor(true);
|
||||||
|
auto item = base::make_unique_q<Ui::Menu::MultilineAction>(
|
||||||
|
_menu,
|
||||||
|
st::defaultMenu,
|
||||||
|
st::historyTranslateCocoonLabel,
|
||||||
|
QPoint(
|
||||||
|
st::defaultMenu.itemPadding.left(),
|
||||||
|
st::defaultMenu.itemPadding.top()),
|
||||||
|
tr::lng_translate_cocoon_menu(
|
||||||
|
tr::now,
|
||||||
|
lt_emoji,
|
||||||
|
Data::SingleCustomEmoji(cocoon),
|
||||||
|
lt_link,
|
||||||
|
tr::link(tr::lng_translate_cocoon_link(tr::now, tr::bold)),
|
||||||
|
tr::rich),
|
||||||
|
Core::TextContext({
|
||||||
|
.session = &_history->session(),
|
||||||
|
.customEmojiLoopLimit = -1,
|
||||||
|
}));
|
||||||
|
item->clicks(
|
||||||
|
) | rpl::on_next([controller = _controller] {
|
||||||
|
controller->show(Box(AboutCocoonBox));
|
||||||
|
}, item->lifetime());
|
||||||
|
_menu->addAction(std::move(item));
|
||||||
|
|
||||||
_menu->popup(_wrap.mapToGlobal(
|
_menu->popup(_wrap.mapToGlobal(
|
||||||
QPoint(_wrap.width(), 0) + st::historyTranslateMenuPosition));
|
QPoint(_wrap.width(), 0) + st::historyTranslateMenuPosition));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -971,6 +971,32 @@ historyTranslateSettings: IconButton(defaultIconButton) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
historyTranslateMenuPosition: point(-6px, 30px);
|
historyTranslateMenuPosition: point(-6px, 30px);
|
||||||
|
historyTranslateCocoonLabel: FlatLabel(historyHasCustomEmoji) {
|
||||||
|
style: TextStyle(defaultTextStyle) {
|
||||||
|
font: font(12px);
|
||||||
|
}
|
||||||
|
margin: margins(4px, 8px, 4px, 8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
cocoonLogoTop: 32px;
|
||||||
|
cocoonLogoSize: 96px;
|
||||||
|
cocoonTitleFont: font(36px semibold);
|
||||||
|
cocoonTitleTop: 12px;
|
||||||
|
cocoonSubtitle: FlatLabel(defaultFlatLabel) {
|
||||||
|
minWidth: 120px;
|
||||||
|
align: align(top);
|
||||||
|
}
|
||||||
|
cocoonSubtitleTop: 8px;
|
||||||
|
cocoonSubtitleBottom: 16px;
|
||||||
|
cocoonJoinSeparatorPadding: margins(24px, 4px, 24px, 12px);
|
||||||
|
cocoonJoinLabel: FlatLabel(defaultFlatLabel) {
|
||||||
|
style: TextStyle(defaultTextStyle) {
|
||||||
|
font: font(12px);
|
||||||
|
}
|
||||||
|
textFg: windowSubTextFg;
|
||||||
|
minWidth: 120px;
|
||||||
|
align: align(top);
|
||||||
|
}
|
||||||
|
|
||||||
historySponsoredAboutMenuLabelPosition: point(54px, 4px);
|
historySponsoredAboutMenuLabelPosition: point(54px, 4px);
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ object_ptr<RpWidget> MakeFeatureListEntry(
|
|||||||
icon->show();
|
icon->show();
|
||||||
title->show();
|
title->show();
|
||||||
about->show();
|
about->show();
|
||||||
|
about->setLinksTrusted();
|
||||||
widget->widthValue(
|
widget->widthValue(
|
||||||
) | rpl::on_next([=](int width) {
|
) | rpl::on_next([=](int width) {
|
||||||
const auto left = st::infoStarsFeatureLabelLeft;
|
const auto left = st::infoStarsFeatureLabelLeft;
|
||||||
|
|||||||
@@ -32,7 +32,31 @@ void StarParticles::setVisible(float visible) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void StarParticles::setColor(const QColor &color) {
|
void StarParticles::setColor(const QColor &color) {
|
||||||
_color = color;
|
setColors({ color });
|
||||||
|
}
|
||||||
|
|
||||||
|
void StarParticles::setColors(std::vector<QColor> colors) {
|
||||||
|
Expects(!colors.empty());
|
||||||
|
|
||||||
|
const auto was = int(_colors.size());
|
||||||
|
_colors = std::move(colors);
|
||||||
|
const auto now = int(_colors.size());
|
||||||
|
|
||||||
|
_paintedCaches.clear();
|
||||||
|
|
||||||
|
if (now != was) {
|
||||||
|
if (now > 1) {
|
||||||
|
auto buffered = base::BufferedRandom<uint32>(_particles.size());
|
||||||
|
for (auto &p : _particles) {
|
||||||
|
p.colorIndex = base::RandomIndex(now, buffered);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (auto &p : _particles) {
|
||||||
|
p.colorIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage StarParticles::generateStarCache(int size, QColor color) {
|
QImage StarParticles::generateStarCache(int size, QColor color) {
|
||||||
@@ -76,12 +100,14 @@ void StarParticles::generate() {
|
|||||||
_particles.clear();
|
_particles.clear();
|
||||||
_particles.reserve(_count);
|
_particles.reserve(_count);
|
||||||
|
|
||||||
constexpr auto kRandomPerParticle = 12;
|
constexpr auto kRandomPerParticle = 13;
|
||||||
auto random = bytes::vector(_count * kRandomPerParticle);
|
auto random = bytes::vector(_count * kRandomPerParticle);
|
||||||
base::RandomFill(random.data(), random.size());
|
base::RandomFill(random.data(), random.size());
|
||||||
auto idx = 0;
|
auto idx = 0;
|
||||||
const auto next = [&] { return uchar(random[idx++]) / 255.; };
|
const auto next = [&] { return uchar(random[idx++]) / 255.; };
|
||||||
|
|
||||||
|
const auto colors = int(_colors.size());
|
||||||
|
|
||||||
for (auto i = 0; i < _count; ++i) {
|
for (auto i = 0; i < _count; ++i) {
|
||||||
auto p = Particle();
|
auto p = Particle();
|
||||||
p.x = next();
|
p.x = next();
|
||||||
@@ -106,6 +132,10 @@ void StarParticles::generate() {
|
|||||||
p.vy = -std::sin(angle) * speed;
|
p.vy = -std::sin(angle) * speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (colors > 1) {
|
||||||
|
p.colorIndex = int(base::SafeRound(next() * (colors - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
_particles.push_back(p);
|
_particles.push_back(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,13 +146,26 @@ void StarParticles::paint(QPainter &p, const QRect &rect, crl::time now) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto colorKey = _color.rgba();
|
const auto validate = [&](int colorIndex) {
|
||||||
const auto i = _starCache.find(colorKey);
|
Expects(colorIndex >= 0 && colorIndex < _colors.size());
|
||||||
const auto &cache = (i != end(_starCache))
|
|
||||||
? i->second
|
if (_paintedCaches.empty()) {
|
||||||
: _starCache.emplace(
|
_paintedCaches.resize(_colors.size());
|
||||||
colorKey,
|
} else if (const auto result = _paintedCaches[colorIndex]
|
||||||
generateStarCache(_starSize, _color)).first->second;
|
; !result.isNull()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const auto &color = _colors[colorIndex];
|
||||||
|
const auto colorKey = color.rgba();
|
||||||
|
const auto i = _starCache.find(colorKey);
|
||||||
|
const auto &cache = (i != end(_starCache))
|
||||||
|
? i->second
|
||||||
|
: _starCache.emplace(
|
||||||
|
colorKey,
|
||||||
|
generateStarCache(_starSize, color)).first->second;
|
||||||
|
_paintedCaches[colorIndex] = cache;
|
||||||
|
return cache;
|
||||||
|
};
|
||||||
|
|
||||||
const auto dt = (now - _lastTime) / 1000.;
|
const auto dt = (now - _lastTime) / 1000.;
|
||||||
_lastTime = now;
|
_lastTime = now;
|
||||||
@@ -147,6 +190,7 @@ void StarParticles::paint(QPainter &p, const QRect &rect, crl::time now) {
|
|||||||
|
|
||||||
const auto x = rect.x() + particle.x * rect.width();
|
const auto x = rect.x() + particle.x * rect.width();
|
||||||
const auto y = rect.y() + particle.y * rect.height();
|
const auto y = rect.y() + particle.y * rect.height();
|
||||||
|
const auto cache = validate(particle.colorIndex);
|
||||||
const auto size = cache.width()
|
const auto size = cache.width()
|
||||||
/ cache.devicePixelRatio() * particle.size;
|
/ cache.devicePixelRatio() * particle.size;
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,12 @@ public:
|
|||||||
void setSpeed(float speed);
|
void setSpeed(float speed);
|
||||||
void setVisible(float visible);
|
void setVisible(float visible);
|
||||||
void setColor(const QColor &color);
|
void setColor(const QColor &color);
|
||||||
|
void setColors(std::vector<QColor> colors);
|
||||||
void paint(QPainter &p, const QRect &rect, crl::time now);
|
void paint(QPainter &p, const QRect &rect, crl::time now);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Particle {
|
struct Particle {
|
||||||
|
int colorIndex = 0;
|
||||||
float x = 0.;
|
float x = 0.;
|
||||||
float y = 0.;
|
float y = 0.;
|
||||||
float vx = 0.;
|
float vx = 0.;
|
||||||
@@ -47,7 +49,8 @@ private:
|
|||||||
int _starSize = 0;
|
int _starSize = 0;
|
||||||
float _speed = 1.f;
|
float _speed = 1.f;
|
||||||
float _visible = 1.f;
|
float _visible = 1.f;
|
||||||
QColor _color = QColor(255, 200, 70);
|
std::vector<QColor> _colors = { QColor(255, 200, 70) };
|
||||||
|
std::vector<QImage> _paintedCaches;
|
||||||
std::vector<Particle> _particles;
|
std::vector<Particle> _particles;
|
||||||
base::flat_map<QRgb, QImage> _starCache;
|
base::flat_map<QRgb, QImage> _starCache;
|
||||||
crl::time _lastTime = 0;
|
crl::time _lastTime = 0;
|
||||||
|
|||||||
+1
-1
Submodule Telegram/lib_ui updated: 07bc368f17...b5b21bbcc5
Reference in New Issue
Block a user