mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-08-14 15:33:38 +00:00
Start non-unique ChatTheme.
This commit is contained in:
@@ -14,11 +14,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/window_controller.h"
|
||||
#include "window/main_window.h"
|
||||
#include "window/window_filters_menu.h"
|
||||
#include "window/themes/window_chat_theme.h"
|
||||
#include "info/info_memento.h"
|
||||
#include "info/info_controller.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "history/view/history_view_replies_section.h"
|
||||
#include "media/player/media_player_instance.h"
|
||||
#include "media/view/media_view_open_common.h"
|
||||
@@ -66,102 +66,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_layers.h" // st::boxLabel
|
||||
#include "styles/style_chat.h" // st::historyMessageRadius
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
|
||||
namespace Window {
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxChatEntryHistorySize = 50;
|
||||
constexpr auto kCacheBackgroundTimeout = 3 * crl::time(1000);
|
||||
constexpr auto kCacheBackgroundFastTimeout = crl::time(200);
|
||||
constexpr auto kBackgroundFadeDuration = crl::time(200);
|
||||
|
||||
[[nodiscard]] CacheBackgroundResult CacheBackground(
|
||||
const CacheBackgroundRequest &request) {
|
||||
const auto gradient = request.gradient.isNull()
|
||||
? QImage()
|
||||
: request.recreateGradient
|
||||
? Images::GenerateGradient(
|
||||
request.gradient.size(),
|
||||
request.gradientColors,
|
||||
request.gradientRotation)
|
||||
: request.gradient;
|
||||
if (request.isPattern || request.tile || request.prepared.isNull()) {
|
||||
auto result = gradient.isNull()
|
||||
? QImage(
|
||||
request.area * cIntRetinaFactor(),
|
||||
QImage::Format_ARGB32_Premultiplied)
|
||||
: gradient.scaled(
|
||||
request.area * cIntRetinaFactor(),
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
result.setDevicePixelRatio(cRetinaFactor());
|
||||
if (!request.prepared.isNull()) {
|
||||
QPainter p(&result);
|
||||
if (!gradient.isNull()) {
|
||||
if (request.patternOpacity >= 0.) {
|
||||
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
||||
p.setOpacity(request.patternOpacity);
|
||||
} else {
|
||||
p.setCompositionMode(
|
||||
QPainter::CompositionMode_DestinationIn);
|
||||
}
|
||||
}
|
||||
const auto tiled = request.isPattern
|
||||
? request.prepared.scaled(
|
||||
request.area.height() * cIntRetinaFactor(),
|
||||
request.area.height() * cIntRetinaFactor(),
|
||||
Qt::KeepAspectRatio,
|
||||
Qt::SmoothTransformation)
|
||||
: request.preparedForTiled;
|
||||
const auto w = tiled.width() / cRetinaFactor();
|
||||
const auto h = tiled.height() / cRetinaFactor();
|
||||
const auto cx = qCeil(request.area.width() / w);
|
||||
const auto cy = qCeil(request.area.height() / h);
|
||||
const auto rows = cy;
|
||||
const auto cols = request.isPattern ? (((cx / 2) * 2) + 1) : cx;
|
||||
const auto xshift = request.isPattern
|
||||
? (request.area.width() - cols * w) / 2
|
||||
: 0;
|
||||
for (auto y = 0; y != rows; ++y) {
|
||||
for (auto x = 0; x != cols; ++x) {
|
||||
p.drawImage(QPointF(xshift + x * w, y * h), tiled);
|
||||
}
|
||||
}
|
||||
if (!gradient.isNull()
|
||||
&& request.patternOpacity < 0.
|
||||
&& request.patternOpacity > -1.) {
|
||||
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
p.setOpacity(1. + request.patternOpacity);
|
||||
p.fillRect(QRect(QPoint(), request.area), Qt::black);
|
||||
}
|
||||
}
|
||||
return {
|
||||
.image = std::move(result).convertToFormat(
|
||||
QImage::Format_ARGB32_Premultiplied),
|
||||
.gradient = gradient,
|
||||
.area = request.area,
|
||||
};
|
||||
} else {
|
||||
const auto rects = Window::Theme::ComputeBackgroundRects(
|
||||
request.area,
|
||||
request.prepared.size());
|
||||
auto result = request.prepared.copy(rects.from).scaled(
|
||||
rects.to.width() * cIntRetinaFactor(),
|
||||
rects.to.height() * cIntRetinaFactor(),
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
result.setDevicePixelRatio(cRetinaFactor());
|
||||
return {
|
||||
.image = std::move(result).convertToFormat(
|
||||
QImage::Format_ARGB32_Premultiplied),
|
||||
.gradient = gradient,
|
||||
.area = request.area,
|
||||
.x = rects.to.x(),
|
||||
.y = rects.to.y(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -550,32 +458,6 @@ void SessionNavigation::showPollResults(
|
||||
showSection(std::make_shared<Info::Memento>(poll, contextId), params);
|
||||
}
|
||||
|
||||
bool operator==(
|
||||
const CacheBackgroundRequest &a,
|
||||
const CacheBackgroundRequest &b) {
|
||||
return (a.prepared.cacheKey() == b.prepared.cacheKey())
|
||||
&& (a.area == b.area)
|
||||
&& (a.gradientRotation == b.gradientRotation)
|
||||
&& (a.tile == b.tile)
|
||||
&& (a.recreateGradient == b.recreateGradient)
|
||||
&& (a.gradient.cacheKey() == b.gradient.cacheKey())
|
||||
&& (a.gradientProgress == b.gradientProgress)
|
||||
&& (a.patternOpacity == b.patternOpacity);
|
||||
}
|
||||
|
||||
bool operator!=(
|
||||
const CacheBackgroundRequest &a,
|
||||
const CacheBackgroundRequest &b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
CachedBackground::CachedBackground(CacheBackgroundResult &&result)
|
||||
: pixmap(Ui::PixmapFromImage(std::move(result.image)))
|
||||
, area(result.area)
|
||||
, x(result.x)
|
||||
, y(result.y) {
|
||||
}
|
||||
|
||||
SessionController::SessionController(
|
||||
not_null<Main::Session*> session,
|
||||
not_null<Controller*> window)
|
||||
@@ -586,7 +468,7 @@ SessionController::SessionController(
|
||||
_window->widget(),
|
||||
this))
|
||||
, _invitePeekTimer([=] { checkInvitePeek(); })
|
||||
, _cacheBackgroundTimer([=] { cacheBackground(); }) {
|
||||
, _defaultChatTheme(std::make_shared<Theme::ChatTheme>()) {
|
||||
init();
|
||||
|
||||
if (Media::Player::instance()->pauseGifByRoundVideo()) {
|
||||
@@ -629,15 +511,6 @@ SessionController::SessionController(
|
||||
}));
|
||||
}, _lifetime);
|
||||
|
||||
using Update = Window::Theme::BackgroundUpdate;
|
||||
Window::Theme::Background()->updates(
|
||||
) | rpl::start_with_next([=](const Update &update) {
|
||||
if (update.type == Update::Type::New
|
||||
|| update.type == Update::Type::Changed) {
|
||||
clearCachedBackground();
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
session->addWindow(this);
|
||||
}
|
||||
|
||||
@@ -1435,23 +1308,50 @@ void SessionController::openDocument(
|
||||
session().data().message(contextId));
|
||||
}
|
||||
|
||||
void SessionController::setBubblesBackground(QImage image) {
|
||||
_bubblesBackgroundPrepared = std::move(image);
|
||||
if (!_bubblesBackground.area.isEmpty()) {
|
||||
_bubblesBackground = CacheBackground({
|
||||
.prepared = _bubblesBackgroundPrepared,
|
||||
.area = _bubblesBackground.area,
|
||||
});
|
||||
auto SessionController::cachedChatThemeValue(
|
||||
const Data::CloudTheme &data)
|
||||
-> rpl::producer<std::shared_ptr<Theme::ChatTheme>> {
|
||||
const auto key = data.id;
|
||||
if (!key || !data.paper || data.paper->backgroundColors().empty()) {
|
||||
return rpl::single(_defaultChatTheme);
|
||||
}
|
||||
if (!_bubblesBackgroundPattern) {
|
||||
_bubblesBackgroundPattern = Ui::PrepareBubblePattern();
|
||||
const auto i = _customChatThemes.find(key);
|
||||
if (i != end(_customChatThemes) && i->second) {
|
||||
return rpl::single(i->second);
|
||||
}
|
||||
_bubblesBackgroundPattern->pixmap = _bubblesBackground.pixmap;
|
||||
_repaintBackgroundRequests.fire({});
|
||||
if (i == end(_customChatThemes)) {
|
||||
cacheChatTheme(data);
|
||||
}
|
||||
using namespace rpl::mappers;
|
||||
return rpl::single(
|
||||
_defaultChatTheme
|
||||
) | rpl::then(_cachedThemesStream.events(
|
||||
) | rpl::filter([=](const std::shared_ptr<Theme::ChatTheme> &theme) {
|
||||
return (theme->key() == key);
|
||||
}) | rpl::take(1));
|
||||
}
|
||||
|
||||
HistoryView::PaintContext SessionController::bubblesContext(
|
||||
BubblesContextArgs &&args) {
|
||||
void SessionController::cacheChatTheme(const Data::CloudTheme &data) {
|
||||
Expects(data.id != 0);
|
||||
|
||||
const auto key = data.id;
|
||||
if (data.paper) {
|
||||
const auto document = data.paper->document();
|
||||
|
||||
}
|
||||
crl::async([this, data, weak = base::make_weak(this)] {
|
||||
crl::on_main(weak, [
|
||||
this,
|
||||
result = std::make_shared<Theme::ChatTheme>(data)
|
||||
]() mutable {
|
||||
_customChatThemes.emplace(result->key(), result);
|
||||
_cachedThemesStream.fire(std::move(result));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
HistoryView::PaintContext SessionController::preparePaintContext(
|
||||
PaintContextArgs &&args) {
|
||||
const auto visibleAreaTopLocal = content()->mapFromGlobal(
|
||||
QPoint(0, args.visibleAreaTopGlobal)).y();
|
||||
const auto viewport = QRect(
|
||||
@@ -1459,205 +1359,7 @@ HistoryView::PaintContext SessionController::bubblesContext(
|
||||
args.visibleAreaTop - visibleAreaTopLocal,
|
||||
args.visibleAreaWidth,
|
||||
content()->height());
|
||||
_bubblesBackground.area = viewport.size();
|
||||
//if (!_bubblesBackgroundPrepared.isNull()
|
||||
// && _bubblesBackground.area != viewport.size()
|
||||
// && !viewport.isEmpty()) {
|
||||
// // #TODO bubbles delayed caching
|
||||
// _bubblesBackground = CacheBackground({
|
||||
// .prepared = _bubblesBackgroundPrepared,
|
||||
// .area = viewport.size(),
|
||||
// });
|
||||
// _bubblesBackgroundPattern->pixmap = _bubblesBackground.pixmap;
|
||||
//}
|
||||
return {
|
||||
.bubblesPattern = _bubblesBackgroundPattern.get(),
|
||||
.viewport = viewport,
|
||||
.clip = args.clip,
|
||||
.now = crl::now(),
|
||||
};
|
||||
}
|
||||
|
||||
const BackgroundState &SessionController::backgroundState(QSize area) {
|
||||
_backgroundState.shown = _backgroundFade.value(1.);
|
||||
if (_backgroundState.now.pixmap.isNull()
|
||||
&& !Window::Theme::Background()->gradientForFill().isNull()) {
|
||||
// We don't support direct painting of patterned gradients.
|
||||
// So we need to sync-generate cache image here.
|
||||
setCachedBackground(CacheBackground(currentCacheRequest(area)));
|
||||
_cacheBackgroundTimer.cancel();
|
||||
} else if (_backgroundState.now.area != area) {
|
||||
if (_willCacheForArea != area
|
||||
|| (!_cacheBackgroundTimer.isActive()
|
||||
&& !_backgroundCachingRequest)) {
|
||||
_willCacheForArea = area;
|
||||
_lastAreaChangeTime = crl::now();
|
||||
_cacheBackgroundTimer.callOnce(kCacheBackgroundFastTimeout);
|
||||
}
|
||||
}
|
||||
generateNextBackgroundRotation();
|
||||
return _backgroundState;
|
||||
}
|
||||
|
||||
bool SessionController::readyForBackgroundRotation() const {
|
||||
return !anim::Disabled()
|
||||
&& !_backgroundFade.animating()
|
||||
&& !_cacheBackgroundTimer.isActive()
|
||||
&& !_backgroundState.now.pixmap.isNull();
|
||||
}
|
||||
|
||||
void SessionController::generateNextBackgroundRotation() {
|
||||
if (_backgroundCachingRequest
|
||||
|| !_backgroundNext.image.isNull()
|
||||
|| !readyForBackgroundRotation()) {
|
||||
return;
|
||||
}
|
||||
const auto background = Window::Theme::Background();
|
||||
if (background->paper().backgroundColors().size() < 3) {
|
||||
return;
|
||||
}
|
||||
constexpr auto kAddRotation = 315;
|
||||
const auto request = currentCacheRequest(
|
||||
_backgroundState.now.area,
|
||||
kAddRotation);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
cacheBackgroundAsync(request, [=](CacheBackgroundResult &&result) {
|
||||
const auto forRequest = base::take(_backgroundCachingRequest);
|
||||
if (!readyForBackgroundRotation()) {
|
||||
return;
|
||||
}
|
||||
const auto request = currentCacheRequest(
|
||||
_backgroundState.now.area,
|
||||
kAddRotation);
|
||||
if (forRequest == request) {
|
||||
_backgroundAddRotation
|
||||
= (_backgroundAddRotation + kAddRotation) % 360;
|
||||
_backgroundNext = std::move(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto SessionController::currentCacheRequest(QSize area, int addRotation) const
|
||||
-> CacheBackgroundRequest {
|
||||
const auto background = Window::Theme::Background();
|
||||
if (background->colorForFill()) {
|
||||
return {};
|
||||
}
|
||||
const auto rotation = background->paper().gradientRotation();
|
||||
const auto gradient = background->gradientForFill();
|
||||
return {
|
||||
.prepared = background->prepared(),
|
||||
.preparedForTiled = background->preparedForTiled(),
|
||||
.area = area,
|
||||
.gradientRotation = (rotation
|
||||
+ _backgroundAddRotation
|
||||
+ addRotation) % 360,
|
||||
.tile = background->tile(),
|
||||
.isPattern = background->paper().isPattern(),
|
||||
.recreateGradient = (addRotation != 0),
|
||||
.gradient = gradient,
|
||||
.gradientColors = (gradient.isNull()
|
||||
? std::vector<QColor>()
|
||||
: background->paper().backgroundColors()),
|
||||
.gradientProgress = 1.,
|
||||
.patternOpacity = background->paper().patternOpacity(),
|
||||
};
|
||||
}
|
||||
|
||||
void SessionController::cacheBackground() {
|
||||
const auto now = crl::now();
|
||||
if (now - _lastAreaChangeTime < kCacheBackgroundTimeout
|
||||
&& QGuiApplication::mouseButtons() != 0) {
|
||||
_cacheBackgroundTimer.callOnce(kCacheBackgroundFastTimeout);
|
||||
return;
|
||||
}
|
||||
cacheBackgroundNow();
|
||||
}
|
||||
|
||||
void SessionController::cacheBackgroundNow() {
|
||||
if (!_backgroundCachingRequest) {
|
||||
if (const auto request = currentCacheRequest(_willCacheForArea)) {
|
||||
cacheBackgroundAsync(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SessionController::cacheBackgroundAsync(
|
||||
const CacheBackgroundRequest &request,
|
||||
Fn<void(CacheBackgroundResult&&)> done) {
|
||||
_backgroundCachingRequest = request;
|
||||
const auto weak = base::make_weak(this);
|
||||
crl::async([=] {
|
||||
if (!weak) {
|
||||
return;
|
||||
}
|
||||
crl::on_main(weak, [=, result = CacheBackground(request)]() mutable {
|
||||
if (done) {
|
||||
done(std::move(result));
|
||||
} else if (const auto request = currentCacheRequest(
|
||||
_willCacheForArea)) {
|
||||
if (_backgroundCachingRequest != request) {
|
||||
cacheBackgroundAsync(request);
|
||||
} else {
|
||||
_backgroundCachingRequest = {};
|
||||
setCachedBackground(std::move(result));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void SessionController::setCachedBackground(CacheBackgroundResult &&cached) {
|
||||
_backgroundNext = {};
|
||||
|
||||
const auto background = Window::Theme::Background();
|
||||
if (background->gradientForFill().isNull()
|
||||
|| _backgroundState.now.pixmap.isNull()
|
||||
|| anim::Disabled()) {
|
||||
_backgroundFade.stop();
|
||||
_backgroundState.shown = 1.;
|
||||
_backgroundState.now = std::move(cached);
|
||||
return;
|
||||
}
|
||||
// #TODO themes compose several transitions.
|
||||
_backgroundState.was = std::move(_backgroundState.now);
|
||||
_backgroundState.now = std::move(cached);
|
||||
_backgroundState.shown = 0.;
|
||||
const auto callback = [=] {
|
||||
if (!_backgroundFade.animating()) {
|
||||
_backgroundState.was = {};
|
||||
_backgroundState.shown = 1.;
|
||||
}
|
||||
_repaintBackgroundRequests.fire({});
|
||||
};
|
||||
_backgroundFade.start(
|
||||
callback,
|
||||
0.,
|
||||
1.,
|
||||
kBackgroundFadeDuration);
|
||||
}
|
||||
|
||||
void SessionController::clearCachedBackground() {
|
||||
_backgroundState = {};
|
||||
_backgroundAddRotation = 0;
|
||||
_backgroundNext = {};
|
||||
_backgroundFade.stop();
|
||||
_cacheBackgroundTimer.cancel();
|
||||
_repaintBackgroundRequests.fire({});
|
||||
}
|
||||
|
||||
rpl::producer<> SessionController::repaintBackgroundRequests() const {
|
||||
return _repaintBackgroundRequests.events();
|
||||
}
|
||||
|
||||
void SessionController::rotateComplexGradientBackground() {
|
||||
if (!_backgroundFade.animating() && !_backgroundNext.image.isNull()) {
|
||||
Window::Theme::Background()->recacheGradientForFill(
|
||||
std::move(_backgroundNext.gradient));
|
||||
setCachedBackground(base::take(_backgroundNext));
|
||||
}
|
||||
return args.theme->preparePaintContext(viewport, args.clip);
|
||||
}
|
||||
|
||||
SessionController::~SessionController() {
|
||||
|
||||
Reference in New Issue
Block a user