mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Create only one EmojiImageLoader to fix a crash.
This commit is contained in:
parent
2e7a89d9c4
commit
51c2bc7349
10 changed files with 234 additions and 152 deletions
|
@ -296,6 +296,8 @@ PRIVATE
|
||||||
chat_helpers/message_field.h
|
chat_helpers/message_field.h
|
||||||
chat_helpers/spellchecker_common.cpp
|
chat_helpers/spellchecker_common.cpp
|
||||||
chat_helpers/spellchecker_common.h
|
chat_helpers/spellchecker_common.h
|
||||||
|
chat_helpers/stickers_emoji_image_loader.cpp
|
||||||
|
chat_helpers/stickers_emoji_image_loader.h
|
||||||
chat_helpers/stickers_emoji_pack.cpp
|
chat_helpers/stickers_emoji_pack.cpp
|
||||||
chat_helpers/stickers_emoji_pack.h
|
chat_helpers/stickers_emoji_pack.h
|
||||||
chat_helpers/stickers_dice_pack.cpp
|
chat_helpers/stickers_dice_pack.cpp
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#include "chat_helpers/stickers_emoji_image_loader.h"
|
||||||
|
|
||||||
|
#include "styles/style_history.h"
|
||||||
|
|
||||||
|
namespace Stickers {
|
||||||
|
|
||||||
|
EmojiImageLoader::EmojiImageLoader(crl::weak_on_queue<EmojiImageLoader> weak)
|
||||||
|
: _weak(std::move(weak)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmojiImageLoader::init(
|
||||||
|
std::shared_ptr<UniversalImages> images,
|
||||||
|
bool largeEnabled) {
|
||||||
|
Expects(images != nullptr);
|
||||||
|
|
||||||
|
_images = std::move(images);
|
||||||
|
if (largeEnabled) {
|
||||||
|
_images->ensureLoaded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage EmojiImageLoader::prepare(EmojiPtr emoji) const {
|
||||||
|
const auto loaded = _images->ensureLoaded();
|
||||||
|
const auto factor = cIntRetinaFactor();
|
||||||
|
const auto side = st::largeEmojiSize + 2 * st::largeEmojiOutline;
|
||||||
|
auto tinted = QImage(
|
||||||
|
QSize(st::largeEmojiSize, st::largeEmojiSize) * factor,
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
tinted.fill(Qt::white);
|
||||||
|
if (loaded) {
|
||||||
|
QPainter p(&tinted);
|
||||||
|
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
|
||||||
|
_images->draw(
|
||||||
|
p,
|
||||||
|
emoji,
|
||||||
|
st::largeEmojiSize * factor,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
auto result = QImage(
|
||||||
|
QSize(side, side) * factor,
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
result.fill(Qt::transparent);
|
||||||
|
if (loaded) {
|
||||||
|
QPainter p(&result);
|
||||||
|
const auto delta = st::largeEmojiOutline * factor;
|
||||||
|
const auto planar = std::array<QPoint, 4>{ {
|
||||||
|
{ 0, -1 },
|
||||||
|
{ -1, 0 },
|
||||||
|
{ 1, 0 },
|
||||||
|
{ 0, 1 },
|
||||||
|
} };
|
||||||
|
for (const auto &shift : planar) {
|
||||||
|
for (auto i = 0; i != delta; ++i) {
|
||||||
|
p.drawImage(QPoint(delta, delta) + shift * (i + 1), tinted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto diagonal = std::array<QPoint, 4>{ {
|
||||||
|
{ -1, -1 },
|
||||||
|
{ 1, -1 },
|
||||||
|
{ -1, 1 },
|
||||||
|
{ 1, 1 },
|
||||||
|
} };
|
||||||
|
const auto corrected = int(std::round(delta / sqrt(2.)));
|
||||||
|
for (const auto &shift : diagonal) {
|
||||||
|
for (auto i = 0; i != corrected; ++i) {
|
||||||
|
p.drawImage(QPoint(delta, delta) + shift * (i + 1), tinted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_images->draw(
|
||||||
|
p,
|
||||||
|
emoji,
|
||||||
|
st::largeEmojiSize * factor,
|
||||||
|
delta,
|
||||||
|
delta);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmojiImageLoader::switchTo(std::shared_ptr<UniversalImages> images) {
|
||||||
|
_images = std::move(images);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto EmojiImageLoader::releaseImages() -> std::shared_ptr<UniversalImages> {
|
||||||
|
return std::exchange(
|
||||||
|
_images,
|
||||||
|
std::make_shared<UniversalImages>(_images->id()));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Stickers
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/emoji_config.h"
|
||||||
|
|
||||||
|
namespace Stickers {
|
||||||
|
|
||||||
|
class EmojiImageLoader {
|
||||||
|
public:
|
||||||
|
using UniversalImages = Ui::Emoji::UniversalImages;
|
||||||
|
|
||||||
|
explicit EmojiImageLoader(crl::weak_on_queue<EmojiImageLoader> weak);
|
||||||
|
|
||||||
|
void init(
|
||||||
|
std::shared_ptr<UniversalImages> images,
|
||||||
|
bool largeEnabled);
|
||||||
|
|
||||||
|
[[nodiscard]] QImage prepare(EmojiPtr emoji) const;
|
||||||
|
void switchTo(std::shared_ptr<UniversalImages> images);
|
||||||
|
std::shared_ptr<UniversalImages> releaseImages();
|
||||||
|
|
||||||
|
private:
|
||||||
|
crl::weak_on_queue<EmojiImageLoader> _weak;
|
||||||
|
std::shared_ptr<UniversalImages> _images;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Stickers
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "chat_helpers/stickers_emoji_pack.h"
|
#include "chat_helpers/stickers_emoji_pack.h"
|
||||||
|
|
||||||
|
#include "chat_helpers/stickers_emoji_image_loader.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "lottie/lottie_common.h"
|
#include "lottie/lottie_common.h"
|
||||||
#include "ui/emoji_config.h"
|
#include "ui/emoji_config.h"
|
||||||
|
@ -26,31 +27,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include <QtCore/QBuffer>
|
#include <QtCore/QBuffer>
|
||||||
|
|
||||||
namespace Stickers {
|
namespace Stickers {
|
||||||
namespace details {
|
|
||||||
|
|
||||||
using UniversalImages = Ui::Emoji::UniversalImages;
|
|
||||||
|
|
||||||
class EmojiImageLoader {
|
|
||||||
public:
|
|
||||||
EmojiImageLoader(
|
|
||||||
crl::weak_on_queue<EmojiImageLoader> weak,
|
|
||||||
std::shared_ptr<UniversalImages> images,
|
|
||||||
bool largeEnabled);
|
|
||||||
|
|
||||||
[[nodiscard]] QImage prepare(EmojiPtr emoji);
|
|
||||||
void switchTo(std::shared_ptr<UniversalImages> images);
|
|
||||||
std::shared_ptr<UniversalImages> releaseImages();
|
|
||||||
|
|
||||||
private:
|
|
||||||
crl::weak_on_queue<EmojiImageLoader> _weak;
|
|
||||||
std::shared_ptr<UniversalImages> _images;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto kRefreshTimeout = 7200 * crl::time(1000);
|
constexpr auto kRefreshTimeout = 7200 * crl::time(1000);
|
||||||
constexpr auto kClearSourceTimeout = 10 * crl::time(1000);
|
|
||||||
|
|
||||||
[[nodiscard]] QSize SingleSize() {
|
[[nodiscard]] QSize SingleSize() {
|
||||||
const auto single = st::largeEmojiSize;
|
const auto single = st::largeEmojiSize;
|
||||||
|
@ -121,97 +100,12 @@ constexpr auto kClearSourceTimeout = 10 * crl::time(1000);
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
EmojiImageLoader::EmojiImageLoader(
|
|
||||||
crl::weak_on_queue<EmojiImageLoader> weak,
|
|
||||||
std::shared_ptr<UniversalImages> images,
|
|
||||||
bool largeEnabled)
|
|
||||||
: _weak(std::move(weak))
|
|
||||||
, _images(std::move(images)) {
|
|
||||||
Expects(_images != nullptr);
|
|
||||||
|
|
||||||
if (largeEnabled) {
|
|
||||||
_images->ensureLoaded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QImage EmojiImageLoader::prepare(EmojiPtr emoji) {
|
|
||||||
const auto loaded = _images->ensureLoaded();
|
|
||||||
const auto factor = cIntRetinaFactor();
|
|
||||||
const auto side = st::largeEmojiSize + 2 * st::largeEmojiOutline;
|
|
||||||
auto tinted = QImage(
|
|
||||||
QSize(st::largeEmojiSize, st::largeEmojiSize) * factor,
|
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
|
||||||
tinted.fill(Qt::white);
|
|
||||||
if (loaded) {
|
|
||||||
QPainter p(&tinted);
|
|
||||||
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
|
|
||||||
_images->draw(
|
|
||||||
p,
|
|
||||||
emoji,
|
|
||||||
st::largeEmojiSize * factor,
|
|
||||||
0,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
auto result = QImage(
|
|
||||||
QSize(side, side) * factor,
|
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
|
||||||
result.fill(Qt::transparent);
|
|
||||||
if (loaded) {
|
|
||||||
QPainter p(&result);
|
|
||||||
const auto delta = st::largeEmojiOutline * factor;
|
|
||||||
const auto planar = std::array<QPoint, 4>{ {
|
|
||||||
{ 0, -1 },
|
|
||||||
{ -1, 0 },
|
|
||||||
{ 1, 0 },
|
|
||||||
{ 0, 1 },
|
|
||||||
} };
|
|
||||||
for (const auto &shift : planar) {
|
|
||||||
for (auto i = 0; i != delta; ++i) {
|
|
||||||
p.drawImage(QPoint(delta, delta) + shift * (i + 1), tinted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const auto diagonal = std::array<QPoint, 4>{ {
|
|
||||||
{ -1, -1 },
|
|
||||||
{ 1, -1 },
|
|
||||||
{ -1, 1 },
|
|
||||||
{ 1, 1 },
|
|
||||||
} };
|
|
||||||
const auto corrected = int(std::round(delta / sqrt(2.)));
|
|
||||||
for (const auto &shift : diagonal) {
|
|
||||||
for (auto i = 0; i != corrected; ++i) {
|
|
||||||
p.drawImage(QPoint(delta, delta) + shift * (i + 1), tinted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_images->draw(
|
|
||||||
p,
|
|
||||||
emoji,
|
|
||||||
st::largeEmojiSize * factor,
|
|
||||||
delta,
|
|
||||||
delta);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmojiImageLoader::switchTo(std::shared_ptr<UniversalImages> images) {
|
|
||||||
_images = std::move(images);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<UniversalImages> EmojiImageLoader::releaseImages() {
|
|
||||||
return std::exchange(
|
|
||||||
_images,
|
|
||||||
std::make_shared<UniversalImages>(_images->id()));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
QSize LargeEmojiImage::Size() {
|
QSize LargeEmojiImage::Size() {
|
||||||
return details::SingleSize();
|
return SingleSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
EmojiPack::EmojiPack(not_null<Main::Session*> session)
|
EmojiPack::EmojiPack(not_null<Main::Session*> session)
|
||||||
: _session(session)
|
: _session(session) {
|
||||||
, _imageLoader(prepareSourceImages(), Core::App().settings().largeEmoji())
|
|
||||||
, _clearTimer([=] { clearSourceImages(); }) {
|
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
session->data().itemRemoved(
|
session->data().itemRemoved(
|
||||||
|
@ -223,22 +117,12 @@ EmojiPack::EmojiPack(not_null<Main::Session*> session)
|
||||||
|
|
||||||
Core::App().settings().largeEmojiChanges(
|
Core::App().settings().largeEmojiChanges(
|
||||||
) | rpl::start_with_next([=](bool large) {
|
) | rpl::start_with_next([=](bool large) {
|
||||||
if (large) {
|
|
||||||
_clearTimer.cancel();
|
|
||||||
} else {
|
|
||||||
_clearTimer.callOnce(details::kClearSourceTimeout);
|
|
||||||
}
|
|
||||||
refreshAll();
|
refreshAll();
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
|
|
||||||
Ui::Emoji::Updated(
|
Ui::Emoji::Updated(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
_images.clear();
|
_images.clear();
|
||||||
_imageLoader.with([
|
|
||||||
source = prepareSourceImages()
|
|
||||||
](details::EmojiImageLoader &loader) mutable {
|
|
||||||
loader.switchTo(std::move(source));
|
|
||||||
});
|
|
||||||
refreshAll();
|
refreshAll();
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
}
|
}
|
||||||
|
@ -286,7 +170,7 @@ auto EmojiPack::stickerForEmoji(const IsolatedEmoji &emoji) -> Sticker {
|
||||||
const auto j = _map.find(first->original());
|
const auto j = _map.find(first->original());
|
||||||
if (j != end(_map)) {
|
if (j != end(_map)) {
|
||||||
const auto index = first->variantIndex(first);
|
const auto index = first->variantIndex(first);
|
||||||
return { j->second.get(), details::ColorReplacements(index) };
|
return { j->second.get(), ColorReplacements(index) };
|
||||||
}
|
}
|
||||||
return Sticker();
|
return Sticker();
|
||||||
}
|
}
|
||||||
|
@ -302,7 +186,8 @@ std::shared_ptr<LargeEmojiImage> EmojiPack::image(EmojiPtr emoji) {
|
||||||
const auto raw = result.get();
|
const auto raw = result.get();
|
||||||
const auto weak = base::make_weak(_session.get());
|
const auto weak = base::make_weak(_session.get());
|
||||||
raw->load = [=] {
|
raw->load = [=] {
|
||||||
_imageLoader.with([=](details::EmojiImageLoader &loader) mutable {
|
Core::App().emojiImageLoader().with([=](
|
||||||
|
const EmojiImageLoader &loader) {
|
||||||
crl::on_main(weak, [
|
crl::on_main(weak, [
|
||||||
=,
|
=,
|
||||||
image = loader.prepare(emoji)
|
image = loader.prepare(emoji)
|
||||||
|
@ -390,24 +275,6 @@ void EmojiPack::refreshItems(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EmojiPack::prepareSourceImages()
|
|
||||||
-> std::shared_ptr<Ui::Emoji::UniversalImages> {
|
|
||||||
const auto &images = Ui::Emoji::SourceImages();
|
|
||||||
if (Core::App().settings().largeEmoji()) {
|
|
||||||
return images;
|
|
||||||
}
|
|
||||||
Ui::Emoji::ClearSourceImages(images);
|
|
||||||
return std::make_shared<Ui::Emoji::UniversalImages>(images->id());
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmojiPack::clearSourceImages() {
|
|
||||||
_imageLoader.with([](details::EmojiImageLoader &loader) {
|
|
||||||
crl::on_main([images = loader.releaseImages()]{
|
|
||||||
Ui::Emoji::ClearSourceImages(images);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmojiPack::applyPack(
|
void EmojiPack::applyPack(
|
||||||
const MTPDstickerPack &data,
|
const MTPDstickerPack &data,
|
||||||
const base::flat_map<uint64, not_null<DocumentData*>> &map) {
|
const base::flat_map<uint64, not_null<DocumentData*>> &map) {
|
||||||
|
@ -442,7 +309,7 @@ base::flat_map<uint64, not_null<DocumentData*>> EmojiPack::collectStickers(
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiPack::refreshDelayed() {
|
void EmojiPack::refreshDelayed() {
|
||||||
base::call_delayed(details::kRefreshTimeout, _session, [=] {
|
base::call_delayed(kRefreshTimeout, _session, [=] {
|
||||||
refresh();
|
refresh();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,6 @@ class UniversalImages;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Stickers {
|
namespace Stickers {
|
||||||
namespace details {
|
|
||||||
class EmojiImageLoader;
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
using IsolatedEmoji = Ui::Text::IsolatedEmoji;
|
using IsolatedEmoji = Ui::Text::IsolatedEmoji;
|
||||||
|
|
||||||
|
@ -84,8 +81,6 @@ private:
|
||||||
void refreshAll();
|
void refreshAll();
|
||||||
void refreshItems(EmojiPtr emoji);
|
void refreshItems(EmojiPtr emoji);
|
||||||
void refreshItems(const base::flat_set<not_null<HistoryItem*>> &list);
|
void refreshItems(const base::flat_set<not_null<HistoryItem*>> &list);
|
||||||
std::shared_ptr<Ui::Emoji::UniversalImages> prepareSourceImages();
|
|
||||||
void clearSourceImages();
|
|
||||||
|
|
||||||
not_null<Main::Session*> _session;
|
not_null<Main::Session*> _session;
|
||||||
base::flat_map<EmojiPtr, not_null<DocumentData*>> _map;
|
base::flat_map<EmojiPtr, not_null<DocumentData*>> _map;
|
||||||
|
@ -95,9 +90,6 @@ private:
|
||||||
base::flat_map<EmojiPtr, std::weak_ptr<LargeEmojiImage>> _images;
|
base::flat_map<EmojiPtr, std::weak_ptr<LargeEmojiImage>> _images;
|
||||||
mtpRequestId _requestId = 0;
|
mtpRequestId _requestId = 0;
|
||||||
|
|
||||||
crl::object_on_queue<details::EmojiImageLoader> _imageLoader;
|
|
||||||
base::Timer _clearTimer;
|
|
||||||
|
|
||||||
rpl::lifetime _lifetime;
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "core/launcher.h"
|
#include "core/launcher.h"
|
||||||
#include "core/ui_integration.h"
|
#include "core/ui_integration.h"
|
||||||
#include "chat_helpers/emoji_keywords.h"
|
#include "chat_helpers/emoji_keywords.h"
|
||||||
|
#include "chat_helpers/stickers_emoji_image_loader.h"
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
#include "platform/platform_specific.h"
|
#include "platform/platform_specific.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
@ -80,6 +81,7 @@ namespace {
|
||||||
|
|
||||||
constexpr auto kQuitPreventTimeoutMs = crl::time(1500);
|
constexpr auto kQuitPreventTimeoutMs = crl::time(1500);
|
||||||
constexpr auto kAutoLockTimeoutLateMs = crl::time(3000);
|
constexpr auto kAutoLockTimeoutLateMs = crl::time(3000);
|
||||||
|
constexpr auto kClearEmojiImageSourceTimeout = 10 * crl::time(1000);
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -96,6 +98,7 @@ Application::Application(not_null<Launcher*> launcher)
|
||||||
, _private(std::make_unique<Private>())
|
, _private(std::make_unique<Private>())
|
||||||
, _databases(std::make_unique<Storage::Databases>())
|
, _databases(std::make_unique<Storage::Databases>())
|
||||||
, _animationsManager(std::make_unique<Ui::Animations::Manager>())
|
, _animationsManager(std::make_unique<Ui::Animations::Manager>())
|
||||||
|
, _clearEmojiImageLoaderTimer([=] { clearEmojiSourceImages(); })
|
||||||
, _fallbackProductionConfig(
|
, _fallbackProductionConfig(
|
||||||
std::make_unique<MTP::Config>(MTP::Environment::Production))
|
std::make_unique<MTP::Config>(MTP::Environment::Production))
|
||||||
, _domain(std::make_unique<Main::Domain>(cDataFile()))
|
, _domain(std::make_unique<Main::Domain>(cDataFile()))
|
||||||
|
@ -207,6 +210,7 @@ void Application::run() {
|
||||||
style::startManager(cScale());
|
style::startManager(cScale());
|
||||||
Ui::InitTextOptions();
|
Ui::InitTextOptions();
|
||||||
Ui::Emoji::Init();
|
Ui::Emoji::Init();
|
||||||
|
startEmojiImageLoader();
|
||||||
Media::Player::start(_audio.get());
|
Media::Player::start(_audio.get());
|
||||||
|
|
||||||
style::ShortAnimationPlaying(
|
style::ShortAnimationPlaying(
|
||||||
|
@ -275,6 +279,24 @@ void Application::run() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Application::prepareEmojiSourceImages()
|
||||||
|
-> std::shared_ptr<Ui::Emoji::UniversalImages> {
|
||||||
|
const auto &images = Ui::Emoji::SourceImages();
|
||||||
|
if (_settings.largeEmoji()) {
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
Ui::Emoji::ClearSourceImages(images);
|
||||||
|
return std::make_shared<Ui::Emoji::UniversalImages>(images->id());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::clearEmojiSourceImages() {
|
||||||
|
_emojiImageLoader.with([](Stickers::EmojiImageLoader &loader) {
|
||||||
|
crl::on_main([images = loader.releaseImages()]{
|
||||||
|
Ui::Emoji::ClearSourceImages(images);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
bool Application::hideMediaView() {
|
bool Application::hideMediaView() {
|
||||||
if (_mediaView && !_mediaView->isHidden()) {
|
if (_mediaView && !_mediaView->isHidden()) {
|
||||||
_mediaView->hide();
|
_mediaView->hide();
|
||||||
|
@ -466,6 +488,34 @@ void Application::startLocalStorage() {
|
||||||
_saveSettingsTimer.setCallback([=] { saveSettings(); });
|
_saveSettingsTimer.setCallback([=] { saveSettings(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::startEmojiImageLoader() {
|
||||||
|
_emojiImageLoader.with([
|
||||||
|
source = prepareEmojiSourceImages(),
|
||||||
|
large = _settings.largeEmoji()
|
||||||
|
](Stickers::EmojiImageLoader &loader) mutable {
|
||||||
|
loader.init(std::move(source), large);
|
||||||
|
});
|
||||||
|
|
||||||
|
_settings.largeEmojiChanges(
|
||||||
|
) | rpl::start_with_next([=](bool large) {
|
||||||
|
if (large) {
|
||||||
|
_clearEmojiImageLoaderTimer.cancel();
|
||||||
|
} else {
|
||||||
|
_clearEmojiImageLoaderTimer.callOnce(
|
||||||
|
kClearEmojiImageSourceTimeout);
|
||||||
|
}
|
||||||
|
}, _lifetime);
|
||||||
|
|
||||||
|
Ui::Emoji::Updated(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
_emojiImageLoader.with([
|
||||||
|
source = prepareEmojiSourceImages()
|
||||||
|
](Stickers::EmojiImageLoader &loader) mutable {
|
||||||
|
loader.switchTo(std::move(source));
|
||||||
|
});
|
||||||
|
}, _lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
void Application::logout(Main::Account *account) {
|
void Application::logout(Main::Account *account) {
|
||||||
if (account) {
|
if (account) {
|
||||||
account->logOut();
|
account->logOut();
|
||||||
|
|
|
@ -51,6 +51,9 @@ namespace Ui {
|
||||||
namespace Animations {
|
namespace Animations {
|
||||||
class Manager;
|
class Manager;
|
||||||
} // namespace Animations
|
} // namespace Animations
|
||||||
|
namespace Emoji {
|
||||||
|
class UniversalImages;
|
||||||
|
} // namespace Emoji
|
||||||
class BoxContent;
|
class BoxContent;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
|
@ -81,6 +84,10 @@ namespace Data {
|
||||||
struct CloudTheme;
|
struct CloudTheme;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
|
namespace Stickers {
|
||||||
|
class EmojiImageLoader;
|
||||||
|
} // namespace Stickers
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
class Launcher;
|
class Launcher;
|
||||||
|
@ -195,6 +202,10 @@ public:
|
||||||
[[nodiscard]] ChatHelpers::EmojiKeywords &emojiKeywords() {
|
[[nodiscard]] ChatHelpers::EmojiKeywords &emojiKeywords() {
|
||||||
return *_emojiKeywords;
|
return *_emojiKeywords;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] auto emojiImageLoader() const
|
||||||
|
-> const crl::object_on_queue<Stickers::EmojiImageLoader> & {
|
||||||
|
return _emojiImageLoader;
|
||||||
|
}
|
||||||
|
|
||||||
// Internal links.
|
// Internal links.
|
||||||
void checkStartUrl();
|
void checkStartUrl();
|
||||||
|
@ -256,8 +267,12 @@ private:
|
||||||
friend bool IsAppLaunched();
|
friend bool IsAppLaunched();
|
||||||
friend Application &App();
|
friend Application &App();
|
||||||
|
|
||||||
|
void clearEmojiSourceImages();
|
||||||
|
[[nodiscard]] auto prepareEmojiSourceImages()
|
||||||
|
-> std::shared_ptr<Ui::Emoji::UniversalImages>;
|
||||||
void startLocalStorage();
|
void startLocalStorage();
|
||||||
void startShortcuts();
|
void startShortcuts();
|
||||||
|
void startEmojiImageLoader();
|
||||||
|
|
||||||
void stateChanged(Qt::ApplicationState state);
|
void stateChanged(Qt::ApplicationState state);
|
||||||
|
|
||||||
|
@ -293,6 +308,8 @@ private:
|
||||||
|
|
||||||
const std::unique_ptr<Storage::Databases> _databases;
|
const std::unique_ptr<Storage::Databases> _databases;
|
||||||
const std::unique_ptr<Ui::Animations::Manager> _animationsManager;
|
const std::unique_ptr<Ui::Animations::Manager> _animationsManager;
|
||||||
|
crl::object_on_queue<Stickers::EmojiImageLoader> _emojiImageLoader;
|
||||||
|
base::Timer _clearEmojiImageLoaderTimer;
|
||||||
mutable std::unique_ptr<MTP::Config> _fallbackProductionConfig;
|
mutable std::unique_ptr<MTP::Config> _fallbackProductionConfig;
|
||||||
const std::unique_ptr<Main::Domain> _domain;
|
const std::unique_ptr<Main::Domain> _domain;
|
||||||
std::unique_ptr<Window::Controller> _window;
|
std::unique_ptr<Window::Controller> _window;
|
||||||
|
|
|
@ -16,7 +16,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "mtproto/mtproto_dc_options.h"
|
#include "mtproto/mtproto_dc_options.h"
|
||||||
#include "storage/storage_domain.h"
|
#include "storage/storage_domain.h"
|
||||||
#include "storage/localstorage.h"
|
#include "storage/localstorage.h"
|
||||||
#include "window/notifications_manager.h"
|
|
||||||
#include "facades.h"
|
#include "facades.h"
|
||||||
|
|
||||||
namespace Main {
|
namespace Main {
|
||||||
|
|
|
@ -200,7 +200,7 @@ void System::clearFromHistory(not_null<History*> history) {
|
||||||
void System::clearFromSession(not_null<Main::Session*> session) {
|
void System::clearFromSession(not_null<Main::Session*> session) {
|
||||||
_manager->clearFromSession(session);
|
_manager->clearFromSession(session);
|
||||||
|
|
||||||
for (auto i = _whenMaps.begin(), e = _whenMaps.end(); i != e;) {
|
for (auto i = _whenMaps.begin(); i != _whenMaps.end();) {
|
||||||
const auto history = i->first;
|
const auto history = i->first;
|
||||||
if (&history->session() == session) {
|
if (&history->session() == session) {
|
||||||
history->clearNotifications();
|
history->clearNotifications();
|
||||||
|
|
|
@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
#include "ui/special_buttons.h"
|
#include "ui/special_buttons.h"
|
||||||
#include "ui/empty_userpic.h"
|
#include "ui/empty_userpic.h"
|
||||||
|
#include "dialogs/dialogs_layout.h"
|
||||||
#include "base/call_delayed.h"
|
#include "base/call_delayed.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "storage/localstorage.h"
|
#include "storage/localstorage.h"
|
||||||
|
@ -91,6 +92,8 @@ private:
|
||||||
const not_null<Main::Account*> _account;
|
const not_null<Main::Account*> _account;
|
||||||
const style::Menu &_st;
|
const style::Menu &_st;
|
||||||
std::shared_ptr<Data::CloudImageView> _userpicView;
|
std::shared_ptr<Data::CloudImageView> _userpicView;
|
||||||
|
|
||||||
|
Dialogs::Layout::UnreadBadgeStyle _unreadSt;
|
||||||
int _unreadBadge = 0;
|
int _unreadBadge = 0;
|
||||||
bool _unreadBadgeMuted = true;
|
bool _unreadBadgeMuted = true;
|
||||||
|
|
||||||
|
@ -161,8 +164,6 @@ void MainMenu::AccountButton::paintEvent(QPaintEvent *e) {
|
||||||
p.fillRect(rect(), over ? _st.itemBgOver : _st.itemBg);
|
p.fillRect(rect(), over ? _st.itemBgOver : _st.itemBg);
|
||||||
paintRipple(p, 0, 0);
|
paintRipple(p, 0, 0);
|
||||||
|
|
||||||
const auto available = width() - 2 * _st.itemPadding.left();
|
|
||||||
|
|
||||||
session.user()->paintUserpicLeft(
|
session.user()->paintUserpicLeft(
|
||||||
p,
|
p,
|
||||||
_userpicView,
|
_userpicView,
|
||||||
|
@ -171,6 +172,29 @@ void MainMenu::AccountButton::paintEvent(QPaintEvent *e) {
|
||||||
width(),
|
width(),
|
||||||
height() - 2 * _st.itemIconPosition.y());
|
height() - 2 * _st.itemIconPosition.y());
|
||||||
|
|
||||||
|
auto available = width() - _st.itemPadding.left();
|
||||||
|
if (_unreadBadge && _account != &Core::App().domain().active()) {
|
||||||
|
_unreadSt.muted = _unreadBadgeMuted;
|
||||||
|
const auto string = (_unreadBadge > 99)
|
||||||
|
? "99+"
|
||||||
|
: QString::number(_unreadBadge);
|
||||||
|
auto unreadWidth = 0;
|
||||||
|
const auto skip = _st.itemPadding.right()
|
||||||
|
- st::mainMenu.itemToggleShift;
|
||||||
|
const auto unreadRight = width() - skip;
|
||||||
|
const auto unreadTop = (height() - _unreadSt.size) / 2;
|
||||||
|
Dialogs::Layout::paintUnreadCount(
|
||||||
|
p,
|
||||||
|
string,
|
||||||
|
unreadRight,
|
||||||
|
unreadTop,
|
||||||
|
_unreadSt,
|
||||||
|
&unreadWidth);
|
||||||
|
available -= unreadWidth + skip + st::mainMenu.itemStyle.font->spacew;
|
||||||
|
} else {
|
||||||
|
available -= _st.itemPadding.right();
|
||||||
|
}
|
||||||
|
|
||||||
p.setPen(over ? _st.itemFgOver : _st.itemFg);
|
p.setPen(over ? _st.itemFgOver : _st.itemFg);
|
||||||
session.user()->nameText().drawElided(
|
session.user()->nameText().drawElided(
|
||||||
p,
|
p,
|
||||||
|
|
Loading…
Add table
Reference in a new issue