Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2024-06-15 18:51:57 +04:00
commit d050cf8ce9
400 changed files with 2718 additions and 2409 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -1,119 +1,115 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "BlueNotificationIcon@2x.png",
"scale" : "2x"
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "BlueNotificationIcon@3x.png",
"scale" : "3x"
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Simple@58x58.png",
"scale" : "2x"
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Simple@87x87.png",
"scale" : "3x"
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Simple@80x80.png",
"scale" : "2x"
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "BlueIcon@2x-1.png",
"scale" : "3x"
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "BlueIcon@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"filename" : "BlueIcon@3x.png",
"scale" : "3x"
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "BlueNotificationIcon.png",
"scale" : "1x"
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "BlueNotificationIcon@2x-1.png",
"scale" : "2x"
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Simple@29x29.png",
"scale" : "1x"
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Simple@58x58-1.png",
"scale" : "2x"
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Simple@40x40-1.png",
"scale" : "1x"
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Simple@80x80-1.png",
"scale" : "2x"
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "BlueIconIpad.png",
"scale" : "1x"
"scale" : "1x",
"size" : "76x76"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "BlueIconIpad@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "BlueIconLargeIpad@2x.png",
"scale" : "2x"
"scale" : "2x",
"size" : "76x76"
},
{
"filename" : "BlueIconLargeIpad@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Simple-iTunesArtwork.png",
"scale" : "1x"
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"pre-rendered" : true
"author" : "xcode",
"version" : 1
}
}
}

View file

@ -18,8 +18,8 @@ CGRect getPathNativeBoundingBox(CGPathRef _Nonnull path);
- (instancetype _Nullable)initWithData:(NSData * _Nonnull)data;
- (void)setFrame:(NSInteger)index;
- (UIImage * _Nullable)renderForSize:(CGSize)size useReferenceRendering:(bool)useReferenceRendering;
- (void)setFrame:(CGFloat)index;
- (UIImage * _Nullable)renderForSize:(CGSize)size useReferenceRendering:(bool)useReferenceRendering canUseMoreMemory:(bool)canUseMoreMemory skipImageGeneration:(bool)skipImageGeneration;
@end

View file

@ -1,5 +1,5 @@
#ifndef CoreGraphicsCanvasImpl_h
#define CoreGraphicsCanvasImpl_h
#ifndef CoreGraphicsCoreGraphicsCanvasImpl_h
#define CoreGraphicsCoreGraphicsCanvasImpl_h
#include <LottieCpp/LottieCpp.h>
@ -7,7 +7,9 @@
namespace lottie {
class CanvasImpl: public Canvas {
class CoreGraphicsCanvasImpl: public Canvas {
class Layer;
public:
class Image {
public:
@ -20,54 +22,39 @@ public:
};
public:
CanvasImpl(int width, int height);
CanvasImpl(CGContextRef context, int width, int height);
virtual ~CanvasImpl();
virtual int width() const override;
virtual int height() const override;
std::shared_ptr<Canvas> makeLayer(int width, int height) override;
CoreGraphicsCanvasImpl(int width, int height);
virtual ~CoreGraphicsCanvasImpl();
virtual void saveState() override;
virtual void restoreState() override;
virtual void fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) override;
virtual void linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override;
virtual void radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override;
virtual void radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, Vector2D const &center, float radius) override;
virtual void strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, lottie::Color const &color) override;
virtual void linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override;
virtual void radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override;
virtual void fill(lottie::CGRect const &rect, lottie::Color const &fillColor) override;
virtual void setBlendMode(BlendMode blendMode) override;
virtual void setAlpha(float alpha) override;
virtual void clip(CGRect const &rect) override;
virtual void concatenate(lottie::Transform2D const &transform) override;
virtual std::shared_ptr<Image> makeImage() const;
virtual void draw(std::shared_ptr<Canvas> const &other, lottie::CGRect const &rect) override;
virtual std::shared_ptr<Image> makeImage();
CGContextRef nativeContext() const {
return _context;
}
virtual bool pushLayer(CGRect const &rect, float alpha, std::optional<MaskMode> maskMode) override;
virtual void popLayer() override;
std::vector<uint8_t> &backingData() {
return _backingData;
}
std::vector<uint8_t> &backingData();
int bytesPerRow();
int bytesPerRow() {
return _bytesPerRow;
}
private:
std::shared_ptr<Layer> &currentLayer();
private:
int _width = 0;
int _height = 0;
int _bytesPerRow = 0;
std::vector<uint8_t> _backingData;
CGContextRef _context = nil;
CGContextRef _topContext = nil;
CGLayerRef _layer = nil;
std::vector<std::shared_ptr<Layer>> _layerStack;
};
}

View file

@ -62,116 +62,136 @@ bool addEnumeratedPath(CGContextRef context, CanvasPathEnumerator const &enumera
}
CanvasImpl::Image::Image(::CGImageRef image) {
class CoreGraphicsCanvasImpl::Layer {
public:
struct Composition {
CGRect rect;
float alpha;
Transform2D transform;
std::optional<Canvas::MaskMode> maskMode;
Composition(CGRect rect_, float alpha_, Transform2D transform_, std::optional<Canvas::MaskMode> maskMode_) :
rect(rect_), alpha(alpha_), transform(transform_), maskMode(maskMode_) {
}
};
public:
explicit Layer(int width, int height, std::optional<Composition> composition) {
_width = width;
_height = height;
_composition = composition;
_bytesPerRow = alignUp(width * 4, 16);
_backingData.resize(_bytesPerRow * _height);
memset(_backingData.data(), 0, _backingData.size());
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst;
_context = CGBitmapContextCreate(_backingData.data(), _width, _height, 8, _bytesPerRow, colorSpace, bitmapInfo);
CFRelease(colorSpace);
CGContextClearRect(_context, CGRectMake(0.0, 0.0, _width, _height));
}
~Layer() {
CGContextRelease(_context);
}
CGContextRef context() const {
return _context;
}
std::optional<Composition> composition() const {
return _composition;
}
std::shared_ptr<CoreGraphicsCanvasImpl::Image> makeImage() {
::CGImageRef nativeImage = CGBitmapContextCreateImage(_context);
if (nativeImage) {
auto image = std::make_shared<CoreGraphicsCanvasImpl::Image>(nativeImage);
CFRelease(nativeImage);
return image;
} else {
return nil;
}
}
public:
CGContextRef _context = nil;
int _width = 0;
int _height = 0;
int _bytesPerRow = 0;
std::vector<uint8_t> _backingData;
std::optional<Composition> _composition;
};
CoreGraphicsCanvasImpl::Image::Image(::CGImageRef image) {
_image = CGImageRetain(image);
}
CanvasImpl::Image::~Image() {
CoreGraphicsCanvasImpl::Image::~Image() {
CFRelease(_image);
}
::CGImageRef CanvasImpl::Image::nativeImage() const {
::CGImageRef CoreGraphicsCanvasImpl::Image::nativeImage() const {
return _image;
}
CanvasImpl::CanvasImpl(int width, int height) {
_width = width;
_height = height;
_bytesPerRow = alignUp(width * 4, 16);
_backingData.resize(_bytesPerRow * _height);
memset(_backingData.data(), 0, _backingData.size());
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst;
_context = CGBitmapContextCreate(_backingData.data(), _width, _height, 8, _bytesPerRow, colorSpace, bitmapInfo);
CGContextClearRect(_context, CGRectMake(0.0, 0.0, _width, _height));
//CGContextSetInterpolationQuality(_context, kCGInterpolationLow);
//CGContextSetAllowsAntialiasing(_context, true);
//CGContextSetShouldAntialias(_context, true);
CFRelease(colorSpace);
_topContext = CGContextRetain(_context);
CoreGraphicsCanvasImpl::CoreGraphicsCanvasImpl(int width, int height) :
_width(width),
_height(height) {
_layerStack.push_back(std::make_shared<Layer>(width, height, std::nullopt));
}
CanvasImpl::CanvasImpl(CGContextRef context, int width, int height) {
_topContext = CGContextRetain(context);
_layer = CGLayerCreateWithContext(context, CGSizeMake(width, height), nil);
_context = CGContextRetain(CGLayerGetContext(_layer));
_width = width;
_height = height;
CoreGraphicsCanvasImpl::~CoreGraphicsCanvasImpl() {
}
CanvasImpl::~CanvasImpl() {
CFRelease(_context);
if (_topContext) {
CFRelease(_topContext);
}
if (_layer) {
CFRelease(_layer);
}
void CoreGraphicsCanvasImpl::saveState() {
CGContextSaveGState(currentLayer()->context());
}
int CanvasImpl::width() const {
return _width;
void CoreGraphicsCanvasImpl::restoreState() {
CGContextRestoreGState(currentLayer()->context());
}
int CanvasImpl::height() const {
return _height;
}
std::shared_ptr<Canvas> CanvasImpl::makeLayer(int width, int height) {
return std::make_shared<CanvasImpl>(_topContext, width, height);
}
void CanvasImpl::saveState() {
CGContextSaveGState(_context);
}
void CanvasImpl::restoreState() {
CGContextRestoreGState(_context);
}
void CanvasImpl::fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) {
if (!addEnumeratedPath(_context, enumeratePath)) {
void CoreGraphicsCanvasImpl::fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) {
if (!addEnumeratedPath(currentLayer()->context(), enumeratePath)) {
return;
}
CGFloat components[4] = { color.r, color.g, color.b, color.a };
CGColorRef nativeColor = CGColorCreate(CGBitmapContextGetColorSpace(_topContext), components);
CGContextSetFillColorWithColor(_context, nativeColor);
CGColorRef nativeColor = CGColorCreate(CGBitmapContextGetColorSpace(currentLayer()->context()), components);
CGContextSetFillColorWithColor(currentLayer()->context(), nativeColor);
CFRelease(nativeColor);
switch (fillRule) {
case lottie::FillRule::EvenOdd: {
CGContextEOFillPath(_context);
CGContextEOFillPath(currentLayer()->context());
break;
}
default: {
CGContextFillPath(_context);
CGContextFillPath(currentLayer()->context());
break;
}
}
}
void CanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) {
CGContextSaveGState(_context);
void CoreGraphicsCanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) {
CGContextSaveGState(currentLayer()->context());
if (!addEnumeratedPath(_context, enumeratePath)) {
CGContextRestoreGState(_context);
if (!addEnumeratedPath(currentLayer()->context(), enumeratePath)) {
CGContextRestoreGState(currentLayer()->context());
return;
}
switch (fillRule) {
case lottie::FillRule::EvenOdd: {
CGContextEOClip(_context);
CGContextEOClip(currentLayer()->context());
break;
}
default: {
CGContextClip(_context);
CGContextClip(currentLayer()->context());
break;
}
}
@ -193,31 +213,31 @@ void CanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumeratePat
locations.push_back(location);
}
CGGradientRef nativeGradient = CGGradientCreateWithColorComponents(CGBitmapContextGetColorSpace(_topContext), components.data(), locations.data(), locations.size());
CGGradientRef nativeGradient = CGGradientCreateWithColorComponents(CGBitmapContextGetColorSpace(currentLayer()->context()), components.data(), locations.data(), locations.size());
if (nativeGradient) {
CGContextDrawLinearGradient(_context, nativeGradient, CGPointMake(start.x, start.y), CGPointMake(end.x, end.y), kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CGContextDrawLinearGradient(currentLayer()->context(), nativeGradient, CGPointMake(start.x, start.y), CGPointMake(end.x, end.y), kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CFRelease(nativeGradient);
}
CGContextResetClip(_context);
CGContextRestoreGState(_context);
CGContextResetClip(currentLayer()->context());
CGContextRestoreGState(currentLayer()->context());
}
void CanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) {
CGContextSaveGState(_context);
void CoreGraphicsCanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, Vector2D const &center, float radius) {
CGContextSaveGState(currentLayer()->context());
if (!addEnumeratedPath(_context, enumeratePath)) {
CGContextRestoreGState(_context);
if (!addEnumeratedPath(currentLayer()->context(), enumeratePath)) {
CGContextRestoreGState(currentLayer()->context());
return;
}
switch (fillRule) {
case lottie::FillRule::EvenOdd: {
CGContextEOClip(_context);
CGContextEOClip(currentLayer()->context());
break;
}
default: {
CGContextClip(_context);
CGContextClip(currentLayer()->context());
break;
}
}
@ -239,62 +259,62 @@ void CanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumeratePat
locations.push_back(location);
}
CGGradientRef nativeGradient = CGGradientCreateWithColorComponents(CGBitmapContextGetColorSpace(_topContext), components.data(), locations.data(), locations.size());
CGGradientRef nativeGradient = CGGradientCreateWithColorComponents(CGBitmapContextGetColorSpace(currentLayer()->context()), components.data(), locations.data(), locations.size());
if (nativeGradient) {
CGContextDrawRadialGradient(_context, nativeGradient, CGPointMake(startCenter.x, startCenter.y), startRadius, CGPointMake(endCenter.x, endCenter.y), endRadius, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CGContextDrawRadialGradient(currentLayer()->context(), nativeGradient, CGPointMake(center.x, center.y), 0.0, CGPointMake(center.x, center.y), radius, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CFRelease(nativeGradient);
}
CGContextResetClip(_context);
CGContextRestoreGState(_context);
CGContextResetClip(currentLayer()->context());
CGContextRestoreGState(currentLayer()->context());
}
void CanvasImpl::strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, lottie::Color const &color) {
if (!addEnumeratedPath(_context, enumeratePath)) {
void CoreGraphicsCanvasImpl::strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, lottie::Color const &color) {
if (!addEnumeratedPath(currentLayer()->context(), enumeratePath)) {
return;
}
CGFloat components[4] = { color.r, color.g, color.b, color.a };
CGColorRef nativeColor = CGColorCreate(CGBitmapContextGetColorSpace(_topContext), components);
CGContextSetStrokeColorWithColor(_context, nativeColor);
CGColorRef nativeColor = CGColorCreate(CGBitmapContextGetColorSpace(currentLayer()->context()), components);
CGContextSetStrokeColorWithColor(currentLayer()->context(), nativeColor);
CFRelease(nativeColor);
CGContextSetLineWidth(_context, lineWidth);
CGContextSetLineWidth(currentLayer()->context(), lineWidth);
switch (lineJoin) {
case lottie::LineJoin::Miter: {
CGContextSetLineJoin(_context, kCGLineJoinMiter);
CGContextSetLineJoin(currentLayer()->context(), kCGLineJoinMiter);
break;
}
case lottie::LineJoin::Round: {
CGContextSetLineJoin(_context, kCGLineJoinRound);
CGContextSetLineJoin(currentLayer()->context(), kCGLineJoinRound);
break;
}
case lottie::LineJoin::Bevel: {
CGContextSetLineJoin(_context, kCGLineJoinBevel);
CGContextSetLineJoin(currentLayer()->context(), kCGLineJoinBevel);
break;
}
default: {
CGContextSetLineJoin(_context, kCGLineJoinBevel);
CGContextSetLineJoin(currentLayer()->context(), kCGLineJoinBevel);
break;
}
}
switch (lineCap) {
case lottie::LineCap::Butt: {
CGContextSetLineCap(_context, kCGLineCapButt);
CGContextSetLineCap(currentLayer()->context(), kCGLineCapButt);
break;
}
case lottie::LineCap::Round: {
CGContextSetLineCap(_context, kCGLineCapRound);
CGContextSetLineCap(currentLayer()->context(), kCGLineCapRound);
break;
}
case lottie::LineCap::Square: {
CGContextSetLineCap(_context, kCGLineCapSquare);
CGContextSetLineCap(currentLayer()->context(), kCGLineCapSquare);
break;
}
default: {
CGContextSetLineCap(_context, kCGLineCapSquare);
CGContextSetLineCap(currentLayer()->context(), kCGLineCapSquare);
break;
}
}
@ -304,54 +324,54 @@ void CanvasImpl::strokePath(CanvasPathEnumerator const &enumeratePath, float lin
for (const auto value : dashPattern) {
mappedDashPattern.push_back(value);
}
CGContextSetLineDash(_context, dashPhase, mappedDashPattern.data(), mappedDashPattern.size());
CGContextSetLineDash(currentLayer()->context(), dashPhase, mappedDashPattern.data(), mappedDashPattern.size());
}
CGContextStrokePath(_context);
CGContextStrokePath(currentLayer()->context());
}
void CanvasImpl::linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) {
CGContextSaveGState(_context);
if (!addEnumeratedPath(_context, enumeratePath)) {
CGContextRestoreGState(_context);
void CoreGraphicsCanvasImpl::linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) {
CGContextSaveGState(currentLayer()->context());
if (!addEnumeratedPath(currentLayer()->context(), enumeratePath)) {
CGContextRestoreGState(currentLayer()->context());
return;
}
CGContextSetLineWidth(_context, lineWidth);
CGContextSetLineWidth(currentLayer()->context(), lineWidth);
switch (lineJoin) {
case lottie::LineJoin::Miter: {
CGContextSetLineJoin(_context, kCGLineJoinMiter);
CGContextSetLineJoin(currentLayer()->context(), kCGLineJoinMiter);
break;
}
case lottie::LineJoin::Round: {
CGContextSetLineJoin(_context, kCGLineJoinRound);
CGContextSetLineJoin(currentLayer()->context(), kCGLineJoinRound);
break;
}
case lottie::LineJoin::Bevel: {
CGContextSetLineJoin(_context, kCGLineJoinBevel);
CGContextSetLineJoin(currentLayer()->context(), kCGLineJoinBevel);
break;
}
default: {
CGContextSetLineJoin(_context, kCGLineJoinBevel);
CGContextSetLineJoin(currentLayer()->context(), kCGLineJoinBevel);
break;
}
}
switch (lineCap) {
case lottie::LineCap::Butt: {
CGContextSetLineCap(_context, kCGLineCapButt);
CGContextSetLineCap(currentLayer()->context(), kCGLineCapButt);
break;
}
case lottie::LineCap::Round: {
CGContextSetLineCap(_context, kCGLineCapRound);
CGContextSetLineCap(currentLayer()->context(), kCGLineCapRound);
break;
}
case lottie::LineCap::Square: {
CGContextSetLineCap(_context, kCGLineCapSquare);
CGContextSetLineCap(currentLayer()->context(), kCGLineCapSquare);
break;
}
default: {
CGContextSetLineCap(_context, kCGLineCapSquare);
CGContextSetLineCap(currentLayer()->context(), kCGLineCapSquare);
break;
}
}
@ -361,11 +381,11 @@ void CanvasImpl::linearGradientStrokePath(CanvasPathEnumerator const &enumerateP
for (const auto value : dashPattern) {
mappedDashPattern.push_back(value);
}
CGContextSetLineDash(_context, dashPhase, mappedDashPattern.data(), mappedDashPattern.size());
CGContextSetLineDash(currentLayer()->context(), dashPhase, mappedDashPattern.data(), mappedDashPattern.size());
}
CGContextReplacePathWithStrokedPath(_context);
CGContextClip(_context);
CGContextReplacePathWithStrokedPath(currentLayer()->context());
CGContextClip(currentLayer()->context());
std::vector<double> components;
components.reserve(gradient.colors().size() + 4);
@ -384,59 +404,59 @@ void CanvasImpl::linearGradientStrokePath(CanvasPathEnumerator const &enumerateP
locations.push_back(location);
}
CGGradientRef nativeGradient = CGGradientCreateWithColorComponents(CGBitmapContextGetColorSpace(_topContext), components.data(), locations.data(), locations.size());
CGGradientRef nativeGradient = CGGradientCreateWithColorComponents(CGBitmapContextGetColorSpace(currentLayer()->context()), components.data(), locations.data(), locations.size());
if (nativeGradient) {
CGContextDrawLinearGradient(_context, nativeGradient, CGPointMake(start.x, start.y), CGPointMake(end.x, end.y), kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CGContextDrawLinearGradient(currentLayer()->context(), nativeGradient, CGPointMake(start.x, start.y), CGPointMake(end.x, end.y), kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CFRelease(nativeGradient);
}
CGContextResetClip(_context);
CGContextRestoreGState(_context);
CGContextResetClip(currentLayer()->context());
CGContextRestoreGState(currentLayer()->context());
}
void CanvasImpl::radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) {
CGContextSaveGState(_context);
if (!addEnumeratedPath(_context, enumeratePath)) {
CGContextRestoreGState(_context);
void CoreGraphicsCanvasImpl::radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) {
CGContextSaveGState(currentLayer()->context());
if (!addEnumeratedPath(currentLayer()->context(), enumeratePath)) {
CGContextRestoreGState(currentLayer()->context());
return;
}
CGContextSetLineWidth(_context, lineWidth);
CGContextSetLineWidth(currentLayer()->context(), lineWidth);
switch (lineJoin) {
case lottie::LineJoin::Miter: {
CGContextSetLineJoin(_context, kCGLineJoinMiter);
CGContextSetLineJoin(currentLayer()->context(), kCGLineJoinMiter);
break;
}
case lottie::LineJoin::Round: {
CGContextSetLineJoin(_context, kCGLineJoinRound);
CGContextSetLineJoin(currentLayer()->context(), kCGLineJoinRound);
break;
}
case lottie::LineJoin::Bevel: {
CGContextSetLineJoin(_context, kCGLineJoinBevel);
CGContextSetLineJoin(currentLayer()->context(), kCGLineJoinBevel);
break;
}
default: {
CGContextSetLineJoin(_context, kCGLineJoinBevel);
CGContextSetLineJoin(currentLayer()->context(), kCGLineJoinBevel);
break;
}
}
switch (lineCap) {
case lottie::LineCap::Butt: {
CGContextSetLineCap(_context, kCGLineCapButt);
CGContextSetLineCap(currentLayer()->context(), kCGLineCapButt);
break;
}
case lottie::LineCap::Round: {
CGContextSetLineCap(_context, kCGLineCapRound);
CGContextSetLineCap(currentLayer()->context(), kCGLineCapRound);
break;
}
case lottie::LineCap::Square: {
CGContextSetLineCap(_context, kCGLineCapSquare);
CGContextSetLineCap(currentLayer()->context(), kCGLineCapSquare);
break;
}
default: {
CGContextSetLineCap(_context, kCGLineCapSquare);
CGContextSetLineCap(currentLayer()->context(), kCGLineCapSquare);
break;
}
}
@ -446,11 +466,11 @@ void CanvasImpl::radialGradientStrokePath(CanvasPathEnumerator const &enumerateP
for (const auto value : dashPattern) {
mappedDashPattern.push_back(value);
}
CGContextSetLineDash(_context, dashPhase, mappedDashPattern.data(), mappedDashPattern.size());
CGContextSetLineDash(currentLayer()->context(), dashPhase, mappedDashPattern.data(), mappedDashPattern.size());
}
CGContextReplacePathWithStrokedPath(_context);
CGContextClip(_context);
CGContextReplacePathWithStrokedPath(currentLayer()->context());
CGContextClip(currentLayer()->context());
std::vector<double> components;
components.reserve(gradient.colors().size() + 4);
@ -469,72 +489,93 @@ void CanvasImpl::radialGradientStrokePath(CanvasPathEnumerator const &enumerateP
locations.push_back(location);
}
CGGradientRef nativeGradient = CGGradientCreateWithColorComponents(CGBitmapContextGetColorSpace(_topContext), components.data(), locations.data(), locations.size());
CGGradientRef nativeGradient = CGGradientCreateWithColorComponents(CGBitmapContextGetColorSpace(currentLayer()->context()), components.data(), locations.data(), locations.size());
if (nativeGradient) {
CGContextDrawRadialGradient(_context, nativeGradient, CGPointMake(startCenter.x, startCenter.y), startRadius, CGPointMake(endCenter.x, endCenter.y), endRadius, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CGContextDrawRadialGradient(currentLayer()->context(), nativeGradient, CGPointMake(startCenter.x, startCenter.y), startRadius, CGPointMake(endCenter.x, endCenter.y), endRadius, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CFRelease(nativeGradient);
}
CGContextResetClip(_context);
CGContextRestoreGState(_context);
CGContextResetClip(currentLayer()->context());
CGContextRestoreGState(currentLayer()->context());
}
void CanvasImpl::fill(lottie::CGRect const &rect, lottie::Color const &fillColor) {
CGFloat components[4] = { fillColor.r, fillColor.g, fillColor.b, fillColor.a };
CGColorRef nativeColor = CGColorCreate(CGBitmapContextGetColorSpace(_topContext), components);
CGContextSetFillColorWithColor(_context, nativeColor);
CFRelease(nativeColor);
void CoreGraphicsCanvasImpl::clip(CGRect const &rect) {
CGContextClipToRect(currentLayer()->context(), CGRectMake(rect.x, rect.y, rect.width, rect.height));
}
void CoreGraphicsCanvasImpl::concatenate(lottie::Transform2D const &transform) {
CGContextConcatCTM(currentLayer()->context(), CATransform3DGetAffineTransform(nativeTransform(transform)));
}
std::shared_ptr<CoreGraphicsCanvasImpl::Image> CoreGraphicsCanvasImpl::makeImage() {
return currentLayer()->makeImage();
}
bool CoreGraphicsCanvasImpl::pushLayer(CGRect const &rect, float alpha, std::optional<Canvas::MaskMode> maskMode) {
auto currentTransform = fromNativeTransform(CATransform3DMakeAffineTransform(CGContextGetCTM(currentLayer()->context())));
CGContextFillRect(_context, CGRectMake(rect.x, rect.y, rect.width, rect.height));
}
void CanvasImpl::setBlendMode(BlendMode blendMode) {
::CGBlendMode nativeMode = kCGBlendModeNormal;
switch (blendMode) {
case BlendMode::Normal: {
nativeMode = kCGBlendModeNormal;
break;
}
case BlendMode::DestinationIn: {
nativeMode = kCGBlendModeDestinationIn;
break;
}
case BlendMode::DestinationOut: {
nativeMode = kCGBlendModeDestinationOut;
break;
}
}
CGContextSetBlendMode(_context, nativeMode);
}
void CanvasImpl::setAlpha(float alpha) {
CGContextSetAlpha(_context, alpha);
}
void CanvasImpl::concatenate(lottie::Transform2D const &transform) {
CGContextConcatCTM(_context, CATransform3DGetAffineTransform(nativeTransform(transform)));
}
std::shared_ptr<CanvasImpl::Image> CanvasImpl::makeImage() const {
::CGImageRef nativeImage = CGBitmapContextCreateImage(_context);
if (nativeImage) {
auto image = std::make_shared<CanvasImpl::Image>(nativeImage);
CFRelease(nativeImage);
return image;
CGRect globalRect(0.0f, 0.0f, 0.0f, 0.0f);
if (rect == CGRect::veryLarge()) {
globalRect = CGRect(0.0f, 0.0f, (float)_width, (float)_height);
} else {
return nil;
CGRect transformedRect = rect.applyingTransform(currentTransform);
CGRect integralTransformedRect(
std::floor(transformedRect.x),
std::floor(transformedRect.y),
std::ceil(transformedRect.width + transformedRect.x - floor(transformedRect.x)),
std::ceil(transformedRect.height + transformedRect.y - floor(transformedRect.y))
);
globalRect = integralTransformedRect.intersection(CGRect(0.0, 0.0, (CGFloat)_width, (CGFloat)_height));
}
if (globalRect.width <= 0.0f || globalRect.height <= 0.0f) {
return false;
}
_layerStack.push_back(std::make_shared<Layer>(globalRect.width, globalRect.height, Layer::Composition(globalRect, alpha, currentTransform, maskMode)));
concatenate(Transform2D::identity().translated(Vector2D(-globalRect.x, -globalRect.y)));
concatenate(currentTransform);
return true;
}
void CoreGraphicsCanvasImpl::popLayer() {
auto layer = _layerStack[_layerStack.size() - 1];
_layerStack.pop_back();
if (const auto composition = layer->composition()) {
saveState();
concatenate(composition->transform.inverted());
CGContextSetAlpha(currentLayer()->context(), composition->alpha);
if (composition->maskMode) {
switch (composition->maskMode.value()) {
case Canvas::MaskMode::Normal: {
CGContextSetBlendMode(currentLayer()->context(), kCGBlendModeDestinationIn);
break;
}
case Canvas::MaskMode::Inverse: {
CGContextSetBlendMode(currentLayer()->context(), kCGBlendModeDestinationOut);
break;
}
default: {
break;
}
}
}
auto image = layer->makeImage();
CGContextDrawImage(currentLayer()->context(), CGRectMake(composition->rect.x, composition->rect.y, composition->rect.width, composition->rect.height), ((CoreGraphicsCanvasImpl::Image *)image.get())->nativeImage());
CGContextSetAlpha(currentLayer()->context(), 1.0);
CGContextSetBlendMode(currentLayer()->context(), kCGBlendModeNormal);
restoreState();
}
}
void CanvasImpl::draw(std::shared_ptr<Canvas> const &other, lottie::CGRect const &rect) {
CanvasImpl *impl = (CanvasImpl *)other.get();
if (impl->_layer) {
CGContextDrawLayerInRect(_context, CGRectMake(rect.x, rect.y, rect.width, rect.height), impl->_layer);
} else {
auto image = impl->makeImage();
CGContextDrawImage(_context, CGRectMake(rect.x, rect.y, rect.width, rect.height), ((CanvasImpl::Image *)image.get())->nativeImage());
}
std::shared_ptr<CoreGraphicsCanvasImpl::Layer> &CoreGraphicsCanvasImpl::currentLayer() {
return _layerStack[_layerStack.size() - 1];
}
}

View file

@ -17,6 +17,8 @@
#include "include/effects/SkDashPathEffect.h"
#include "include/effects/SkGradientShader.h"
#include <cfloat>
namespace lottie {
namespace {
@ -50,8 +52,7 @@ void skPath(CanvasPathEnumerator const &enumeratePath, SkPath &nativePath) {
}
SkiaCanvasImpl::SkiaCanvasImpl(int width, int height) :
_width(width), _height(height) {
SkiaCanvasImpl::SkiaCanvasImpl(int width, int height) {
int bytesPerRow = width * 4;
_pixelData = malloc(bytesPerRow * height);
_ownsPixelData = true;
@ -90,18 +91,6 @@ SkiaCanvasImpl::~SkiaCanvasImpl() {
}
}
int SkiaCanvasImpl::width() const {
return _width;
}
int SkiaCanvasImpl::height() const {
return _height;
}
std::shared_ptr<Canvas> SkiaCanvasImpl::makeLayer(int width, int height) {
return std::make_shared<SkiaCanvasImpl>(width, height);
}
void SkiaCanvasImpl::saveState() {
_canvas->save();
}
@ -113,9 +102,7 @@ void SkiaCanvasImpl::restoreState() {
void SkiaCanvasImpl::fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) {
SkPaint paint;
paint.setColor(skColor(color));
paint.setAlphaf(_alpha);
paint.setAntiAlias(true);
paint.setBlendMode(_blendMode);
SkPath nativePath;
skPath(enumeratePath, nativePath);
@ -127,7 +114,6 @@ void SkiaCanvasImpl::fillPath(CanvasPathEnumerator const &enumeratePath, lottie:
void SkiaCanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setBlendMode(_blendMode);
paint.setDither(false);
paint.setStyle(SkPaint::Style::kFill_Style);
@ -138,7 +124,7 @@ void SkiaCanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumerat
std::vector<SkColor> colors;
for (const auto &color : gradient.colors()) {
colors.push_back(skColor(Color(color.r, color.g, color.b, color.a * _alpha)));
colors.push_back(skColor(Color(color.r, color.g, color.b, color.a)));
}
std::vector<SkScalar> locations;
@ -146,7 +132,7 @@ void SkiaCanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumerat
locations.push_back(location);
}
paint.setShader(SkGradientShader::MakeLinear(linearPoints, colors.data(), locations.data(), (int)colors.size(), SkTileMode::kMirror));
paint.setShader(SkGradientShader::MakeLinear(linearPoints, colors.data(), locations.data(), (int)colors.size(), SkTileMode::kClamp));
SkPath nativePath;
skPath(enumeratePath, nativePath);
@ -155,16 +141,14 @@ void SkiaCanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumerat
_canvas->drawPath(nativePath, paint);
}
void SkiaCanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) {
void SkiaCanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Gradient const &gradient, Vector2D const &center, float radius) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setBlendMode(_blendMode);
paint.setDither(false);
paint.setStyle(SkPaint::Style::kFill_Style);
std::vector<SkColor> colors;
for (const auto &color : gradient.colors()) {
colors.push_back(skColor(Color(color.r, color.g, color.b, color.a * _alpha)));
colors.push_back(skColor(Color(color.r, color.g, color.b, color.a)));
}
std::vector<SkScalar> locations;
@ -172,7 +156,7 @@ void SkiaCanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumerat
locations.push_back(location);
}
paint.setShader(SkGradientShader::MakeRadial(SkPoint::Make(startCenter.x, startCenter.y), endRadius, colors.data(), locations.data(), (int)colors.size(), SkTileMode::kMirror));
paint.setShader(SkGradientShader::MakeRadial(SkPoint::Make(center.x, center.y), radius, colors.data(), locations.data(), (int)colors.size(), SkTileMode::kClamp));
SkPath nativePath;
skPath(enumeratePath, nativePath);
@ -182,11 +166,12 @@ void SkiaCanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumerat
}
void SkiaCanvasImpl::strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, lottie::Color const &color) {
if (lineWidth <= FLT_EPSILON) {
return;
}
SkPaint paint;
paint.setAntiAlias(true);
paint.setBlendMode(_blendMode);
paint.setColor(skColor(color));
paint.setAlphaf(_alpha);
paint.setStyle(SkPaint::Style::kStroke_Style);
paint.setStrokeWidth(lineWidth);
@ -234,6 +219,9 @@ void SkiaCanvasImpl::strokePath(CanvasPathEnumerator const &enumeratePath, float
for (auto value : dashPattern) {
intervals.push_back(value);
}
if (intervals.size() == 1) {
intervals.push_back(intervals[0]);
}
paint.setPathEffect(SkDashPathEffect::Make(intervals.data(), (int)intervals.size(), dashPhase));
}
@ -251,39 +239,8 @@ void SkiaCanvasImpl::radialGradientStrokePath(CanvasPathEnumerator const &enumer
assert(false);
}
void SkiaCanvasImpl::fill(lottie::CGRect const &rect, lottie::Color const &fillColor) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(skColor(fillColor));
paint.setAlphaf(_alpha);
paint.setBlendMode(_blendMode);
_canvas->drawRect(SkRect::MakeXYWH(rect.x, rect.y, rect.width, rect.height), paint);
}
void SkiaCanvasImpl::setBlendMode(BlendMode blendMode) {
switch (blendMode) {
case BlendMode::Normal: {
_blendMode = SkBlendMode::kSrcOver;
break;
}
case BlendMode::DestinationIn: {
_blendMode = SkBlendMode::kDstIn;
break;
}
case BlendMode::DestinationOut: {
_blendMode = SkBlendMode::kDstOut;
break;
}
default: {
_blendMode = SkBlendMode::kSrcOver;
break;
}
}
}
void SkiaCanvasImpl::setAlpha(float alpha) {
_alpha = alpha;
void SkiaCanvasImpl::clip(CGRect const &rect) {
_canvas->clipRect(SkRect::MakeXYWH(rect.x, rect.y, rect.width, rect.height), true);
}
void SkiaCanvasImpl::concatenate(lottie::Transform2D const &transform) {
@ -297,13 +254,32 @@ void SkiaCanvasImpl::concatenate(lottie::Transform2D const &transform) {
_canvas->concat(matrix);
}
void SkiaCanvasImpl::draw(std::shared_ptr<Canvas> const &other, lottie::CGRect const &rect) {
SkiaCanvasImpl *impl = (SkiaCanvasImpl *)other.get();
auto image = impl->surface()->makeImageSnapshot();
bool SkiaCanvasImpl::pushLayer(CGRect const &rect, float alpha, std::optional<MaskMode> maskMode) {
SkPaint paint;
paint.setBlendMode(_blendMode);
paint.setAlphaf(_alpha);
_canvas->drawImageRect(image.get(), SkRect::MakeXYWH(rect.x, rect.y, rect.width, rect.height), SkSamplingOptions(SkFilterMode::kLinear), &paint);
paint.setAntiAlias(true);
paint.setAlphaf(alpha);
if (maskMode) {
switch (maskMode.value()) {
case Canvas::MaskMode::Normal: {
paint.setBlendMode(SkBlendMode::kDstIn);
break;
}
case Canvas::MaskMode::Inverse: {
paint.setBlendMode(SkBlendMode::kDstOut);
break;
}
default: {
break;
}
}
}
_canvas->saveLayer(SkRect::MakeXYWH(rect.x, rect.y, rect.width, rect.height), &paint);
return true;
}
void SkiaCanvasImpl::popLayer() {
_canvas->restore();
}
void SkiaCanvasImpl::flush() {

View file

@ -14,29 +14,21 @@ public:
SkiaCanvasImpl(int width, int height, int bytesPerRow, void *pixelData);
virtual ~SkiaCanvasImpl();
virtual int width() const override;
virtual int height() const override;
virtual std::shared_ptr<Canvas> makeLayer(int width, int height) override;
virtual void saveState() override;
virtual void restoreState() override;
virtual void fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) override;
virtual void linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override;
virtual void radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override;
virtual void radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Gradient const &gradient, Vector2D const &center, float radius) override;
virtual void strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, lottie::Color const &color) override;
virtual void linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override;
virtual void radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override;
virtual void fill(lottie::CGRect const &rect, lottie::Color const &fillColor) override;
virtual void setBlendMode(BlendMode blendMode) override;
virtual void setAlpha(float alpha) override;
virtual void clip(CGRect const &rect) override;
virtual void concatenate(lottie::Transform2D const &transform) override;
virtual void draw(std::shared_ptr<Canvas> const &other, lottie::CGRect const &rect) override;
virtual bool pushLayer(CGRect const &rect, float alpha, std::optional<MaskMode> maskMode) override;
virtual void popLayer() override;
void flush();
sk_sp<SkSurface> surface() const;
@ -44,12 +36,8 @@ public:
private:
void *_pixelData = nullptr;
bool _ownsPixelData = false;
int _width = 0;
int _height = 0;
sk_sp<SkSurface> _surface;
SkCanvas *_canvas = nullptr;
SkBlendMode _blendMode = SkBlendMode::kSrcOver;
double _alpha = 1.0;
};
}

View file

@ -53,102 +53,66 @@ CGRect getPathNativeBoundingBox(CGPathRef _Nonnull path) {
return CGSizeMake(size.x, size.y);
}
- (void)setFrame:(NSInteger)index {
_renderer->setFrame((int)index);
- (void)setFrame:(CGFloat)index {
_renderer->setFrame((float)index);
}
- (UIImage * _Nullable)renderForSize:(CGSize)size useReferenceRendering:(bool)useReferenceRendering {
- (UIImage * _Nullable)renderForSize:(CGSize)size useReferenceRendering:(bool)useReferenceRendering canUseMoreMemory:(bool)canUseMoreMemory skipImageGeneration:(bool)skipImageGeneration {
std::shared_ptr<lottie::RenderTreeNode> renderNode = _renderer->renderNode();
if (!renderNode) {
return nil;
}
lottie::CanvasRenderer::Configuration configuration;
configuration.canUseMoreMemory = canUseMoreMemory;
//configuration.canUseMoreMemory = true;
//configuration.disableGroupTransparency = true;
if (useReferenceRendering) {
auto context = std::make_shared<lottie::CanvasImpl>((int)size.width, (int)size.height);
auto context = std::make_shared<lottie::CoreGraphicsCanvasImpl>((int)size.width, (int)size.height);
_canvasRenderer->render(_renderer, context, lottie::Vector2D(size.width, size.height));
_canvasRenderer->render(_renderer, context, lottie::Vector2D(size.width, size.height), configuration);
auto image = context->makeImage();
return [[UIImage alloc] initWithCGImage:std::static_pointer_cast<lottie::CanvasImpl::Image>(image)->nativeImage()];
return [[UIImage alloc] initWithCGImage:std::static_pointer_cast<lottie::CoreGraphicsCanvasImpl::Image>(image)->nativeImage()];
} else {
if ((int64_t)"" > 0) {
/*auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul((int)size.width, (int)size.height));
int bytesPerRow = ((int)size.width) * 4;
void *pixelData = malloc(bytesPerRow * (int)size.height);
sk_sp<SkSurface> surface2 = SkSurfaces::WrapPixels(
SkImageInfo::MakeN32Premul((int)size.width, (int)size.height),
pixelData,
bytesPerRow,
nullptr
);
SkCanvas *canvas = surface->getCanvas();
SkPaint paint;
paint.setAntiAlias(true);
SkPath path;
path.moveTo(124, 108);
path.lineTo(172, 24);
path.addCircle(50, 50, 30);
path.moveTo(36, 148);
path.quadTo(66, 188, 120, 136);
canvas->drawPath(path, paint);
paint.setStyle(SkPaint::kStroke_Style);
paint.setColor(SK_ColorBLUE);
paint.setStrokeWidth(3);
canvas->drawPath(path, paint);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
CGContextRef targetContext = CGBitmapContextCreate(pixelData, (int)size.width, (int)size.height, 8, bytesPerRow, colorSpace, bitmapInfo);
CGColorSpaceRelease(colorSpace);
CGImageRef bitmapImage = CGBitmapContextCreateImage(targetContext);
UIImage *image = [[UIImage alloc] initWithCGImage:bitmapImage scale:1.0f orientation:UIImageOrientationDownMirrored];
CGImageRelease(bitmapImage);
CGContextRelease(targetContext);
free(pixelData);
return image;*/
int bytesPerRow = ((int)size.width) * 4;
void *pixelData = malloc(bytesPerRow * (int)size.height);
auto context = std::make_shared<lottie::SkiaCanvasImpl>((int)size.width, (int)size.height, bytesPerRow, pixelData);
_canvasRenderer->render(_renderer, context, lottie::Vector2D(size.width, size.height));
_canvasRenderer->render(_renderer, context, lottie::Vector2D(size.width, size.height), configuration);
context->flush();
vImage_Buffer src;
src.data = (void *)pixelData;
src.width = (int)size.width;
src.height = (int)size.height;
src.rowBytes = bytesPerRow;
uint8_t permuteMap[4] = {2, 1, 0, 3};
vImagePermuteChannels_ARGB8888(&src, &src, permuteMap, kvImageDoNotTile);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
CGContextRef targetContext = CGBitmapContextCreate(pixelData, (int)size.width, (int)size.height, 8, bytesPerRow, colorSpace, bitmapInfo);
CGColorSpaceRelease(colorSpace);
CGImageRef bitmapImage = CGBitmapContextCreateImage(targetContext);
UIImage *image = [[UIImage alloc] initWithCGImage:bitmapImage scale:1.0f orientation:UIImageOrientationDownMirrored];
CGImageRelease(bitmapImage);
CGContextRelease(targetContext);
free(pixelData);
return image;
if (skipImageGeneration) {
free(pixelData);
} else {
vImage_Buffer src;
src.data = (void *)pixelData;
src.width = (int)size.width;
src.height = (int)size.height;
src.rowBytes = bytesPerRow;
uint8_t permuteMap[4] = {2, 1, 0, 3};
vImagePermuteChannels_ARGB8888(&src, &src, permuteMap, kvImageDoNotTile);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
CGContextRef targetContext = CGBitmapContextCreate(pixelData, (int)size.width, (int)size.height, 8, bytesPerRow, colorSpace, bitmapInfo);
CGColorSpaceRelease(colorSpace);
CGImageRef bitmapImage = CGBitmapContextCreateImage(targetContext);
UIImage *image = [[UIImage alloc] initWithCGImage:bitmapImage scale:1.0f orientation:UIImageOrientationDownMirrored];
CGImageRelease(bitmapImage);
CGContextRelease(targetContext);
free(pixelData);
return image;
}
} else if ((int64_t)"" < 0) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
@ -158,7 +122,7 @@ CGRect getPathNativeBoundingBox(CGPathRef _Nonnull path) {
int bytesPerRow = ((int)size.width) * 4;
auto context = std::make_shared<lottie::ThorVGCanvasImpl>((int)size.width, (int)size.height, bytesPerRow);
_canvasRenderer->render(_renderer, context, lottie::Vector2D(size.width, size.height));
_canvasRenderer->render(_renderer, context, lottie::Vector2D(size.width, size.height), configuration);
context->flush();
@ -177,7 +141,7 @@ CGRect getPathNativeBoundingBox(CGPathRef _Nonnull path) {
return image;
} else {
auto context = std::make_shared<lottie::NullCanvasImpl>((int)size.width, (int)size.height);
_canvasRenderer->render(_renderer, context, lottie::Vector2D(size.width, size.height));
_canvasRenderer->render(_renderer, context, lottie::Vector2D(size.width, size.height), configuration);
return nil;
}

View file

@ -49,7 +49,7 @@ void ThorVGCanvasImpl::initializeOnce() {
}
ThorVGCanvasImpl::ThorVGCanvasImpl(int width, int height, int bytesPerRow) :
_width(width), _height(height), _transform(lottie::Transform2D::identity()) {
_transform(lottie::Transform2D::identity()) {
_canvas = tvg::SwCanvas::gen();
_bytesPerRow = bytesPerRow;
@ -63,18 +63,6 @@ _width(width), _height(height), _transform(lottie::Transform2D::identity()) {
ThorVGCanvasImpl::~ThorVGCanvasImpl() {
}
int ThorVGCanvasImpl::width() const {
return _width;
}
int ThorVGCanvasImpl::height() const {
return _height;
}
std::shared_ptr<Canvas> ThorVGCanvasImpl::makeLayer(int width, int height) {
return std::make_shared<ThorVGCanvasImpl>(width, height, width * 4);
}
void ThorVGCanvasImpl::saveState() {
_stateStack.push_back(_transform);
}
@ -94,7 +82,7 @@ void ThorVGCanvasImpl::fillPath(CanvasPathEnumerator const &enumeratePath, lotti
shape->transform(tvgTransform(_transform));
shape->fill((int)(color.r * 255.0), (int)(color.g * 255.0), (int)(color.b * 255.0), (int)(color.a * _alpha * 255.0));
shape->fill((int)(color.r * 255.0), (int)(color.g * 255.0), (int)(color.b * 255.0), (int)(color.a * 255.0));
shape->fill(fillRule == lottie::FillRule::EvenOdd ? tvg::FillRule::EvenOdd : tvg::FillRule::Winding);
_canvas->push(std::move(shape));
@ -117,7 +105,7 @@ void ThorVGCanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumer
colorStop.r = (int)(color.r * 255.0);
colorStop.g = (int)(color.g * 255.0);
colorStop.b = (int)(color.b * 255.0);
colorStop.a = (int)(color.a * _alpha * 255.0);
colorStop.a = (int)(color.a * 255.0);
colors.push_back(colorStop);
}
fill->colorStops(colors.data(), (uint32_t)colors.size());
@ -128,14 +116,14 @@ void ThorVGCanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumer
_canvas->push(std::move(shape));
}
void ThorVGCanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) {
void ThorVGCanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, Vector2D const &center, float radius) {
auto shape = tvg::Shape::gen();
tvgPath(enumeratePath, shape.get());
shape->transform(tvgTransform(_transform));
auto fill = tvg::RadialGradient::gen();
fill->radial(startCenter.x, startCenter.y, endRadius);
fill->radial(center.x, center.y, radius);
std::vector<tvg::Fill::ColorStop> colors;
for (size_t i = 0; i < gradient.colors().size(); i++) {
@ -145,7 +133,7 @@ void ThorVGCanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumer
colorStop.r = (int)(color.r * 255.0);
colorStop.g = (int)(color.g * 255.0);
colorStop.b = (int)(color.b * 255.0);
colorStop.a = (int)(color.a * _alpha * 255.0);
colorStop.a = (int)(color.a * 255.0);
colors.push_back(colorStop);
}
fill->colorStops(colors.data(), (uint32_t)colors.size());
@ -162,7 +150,7 @@ void ThorVGCanvasImpl::strokePath(CanvasPathEnumerator const &enumeratePath, flo
shape->transform(tvgTransform(_transform));
shape->strokeFill((int)(color.r * 255.0), (int)(color.g * 255.0), (int)(color.b * 255.0), (int)(color.a * _alpha * 255.0));
shape->strokeFill((int)(color.r * 255.0), (int)(color.g * 255.0), (int)(color.b * 255.0), (int)(color.a * 255.0));
shape->strokeWidth(lineWidth);
switch (lineJoin) {
@ -222,59 +210,8 @@ void ThorVGCanvasImpl::linearGradientStrokePath(CanvasPathEnumerator const &enum
void ThorVGCanvasImpl::radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) {
}
void ThorVGCanvasImpl::fill(lottie::CGRect const &rect, lottie::Color const &fillColor) {
auto shape = tvg::Shape::gen();
shape->appendRect(rect.x, rect.y, rect.width, rect.height, 0.0f, 0.0f);
shape->transform(tvgTransform(_transform));
shape->fill((int)(fillColor.r * 255.0), (int)(fillColor.g * 255.0), (int)(fillColor.b * 255.0), (int)(fillColor.a * _alpha * 255.0));
_canvas->push(std::move(shape));
}
void ThorVGCanvasImpl::setBlendMode(BlendMode blendMode) {
/*switch (blendMode) {
case CGBlendMode::Normal: {
_blendMode = SkBlendMode::kSrcOver;
break;
}
case CGBlendMode::DestinationIn: {
_blendMode = SkBlendMode::kDstIn;
break;
}
case CGBlendMode::DestinationOut: {
_blendMode = SkBlendMode::kDstOut;
break;
}
default: {
_blendMode = SkBlendMode::kSrcOver;
break;
}
}*/
}
void ThorVGCanvasImpl::setAlpha(float alpha) {
_alpha = alpha;
}
void ThorVGCanvasImpl::concatenate(lottie::Transform2D const &transform) {
_transform = transform * _transform;
/*_canvas->concat(SkM44(
transform.m11, transform.m21, transform.m31, transform.m41,
transform.m12, transform.m22, transform.m32, transform.m42,
transform.m13, transform.m23, transform.m33, transform.m43,
transform.m14, transform.m24, transform.m34, transform.m44
));*/
}
void ThorVGCanvasImpl::draw(std::shared_ptr<Canvas> const &other, lottie::CGRect const &rect) {
/*ThorVGCanvasImpl *impl = (ThorVGCanvasImpl *)other.get();
auto image = impl->surface()->makeImageSnapshot();
SkPaint paint;
paint.setBlendMode(_blendMode);
paint.setAlphaf(_alpha);
_canvas->drawImageRect(image.get(), SkRect::MakeXYWH(rect.x, rect.y, rect.width, rect.height), SkSamplingOptions(SkFilterMode::kLinear), &paint);*/
}
void ThorVGCanvasImpl::flush() {

View file

@ -14,30 +14,18 @@ public:
ThorVGCanvasImpl(int width, int height, int bytesPerRow);
virtual ~ThorVGCanvasImpl();
virtual int width() const override;
virtual int height() const override;
virtual std::shared_ptr<Canvas> makeLayer(int width, int height) override;
virtual void saveState() override;
virtual void restoreState() override;
virtual void fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) override;
virtual void linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override;
virtual void radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override;
virtual void radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Gradient const &gradient, Vector2D const &center, float radius) override;
virtual void strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, lottie::Color const &color) override;
virtual void linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override;
virtual void radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override;
virtual void fill(lottie::CGRect const &rect, lottie::Color const &fillColor) override;
virtual void setBlendMode(BlendMode blendMode) override;
virtual void setAlpha(float alpha) override;
virtual void concatenate(lottie::Transform2D const &transform) override;
virtual void draw(std::shared_ptr<Canvas> const &other, lottie::CGRect const &rect) override;
uint32_t *backingData() {
return _backingData;
}
@ -49,11 +37,8 @@ public:
void flush();
private:
int _width = 0;
int _height = 0;
std::unique_ptr<tvg::SwCanvas> _canvas;
float _alpha = 1.0;
lottie::Transform2D _transform;
std::vector<lottie::Transform2D> _stateStack;
int _bytesPerRow = 0;

View file

@ -10,17 +10,26 @@ import SoftwareLottieRenderer
import LottieSwift
@available(iOS 13.0, *)
func areImagesEqual(_ lhs: UIImage, _ rhs: UIImage) -> UIImage? {
func areImagesEqual(_ lhs: UIImage, _ rhs: UIImage, allowedDifference: Double) -> (UIImage?, UIImage) {
let lhsBuffer = try! vImage_Buffer(cgImage: lhs.cgImage!)
let rhsBuffer = try! vImage_Buffer(cgImage: rhs.cgImage!)
let deltaBuffer = try! vImage_Buffer(cgImage: lhs.cgImage!)
defer {
lhsBuffer.free()
rhsBuffer.free()
deltaBuffer.free()
}
let maxDifferenceCount = Int((Double(Int(lhs.size.width) * Int(lhs.size.height)) * 0.01))
memset(deltaBuffer.data, 0, Int(deltaBuffer.height) * deltaBuffer.rowBytes)
let maxDifferenceCount = Int((Double(Int(lhs.size.width) * Int(lhs.size.height)) * allowedDifference))
var foundDifferenceCount = 0
outer: for y in 0 ..< Int(lhs.size.height) {
let lhsRowPixels = lhsBuffer.data.assumingMemoryBound(to: UInt8.self).advanced(by: y * lhsBuffer.rowBytes)
let rhsRowPixels = rhsBuffer.data.assumingMemoryBound(to: UInt8.self).advanced(by: y * lhsBuffer.rowBytes)
let deltaRowPixels = deltaBuffer.data.assumingMemoryBound(to: UInt8.self).advanced(by: y * lhsBuffer.rowBytes)
for x in 0 ..< Int(lhs.size.width) {
let lhs0 = lhsRowPixels.advanced(by: x * 4 + 0).pointee
@ -36,32 +45,30 @@ func areImagesEqual(_ lhs: UIImage, _ rhs: UIImage) -> UIImage? {
let maxDiff = 25
if abs(Int(lhs0) - Int(rhs0)) > maxDiff || abs(Int(lhs1) - Int(rhs1)) > maxDiff || abs(Int(lhs2) - Int(rhs2)) > maxDiff || abs(Int(lhs3) - Int(rhs3)) > maxDiff {
/*if false {
lhsRowPixels.advanced(by: x * 4 + 0).pointee = 255
lhsRowPixels.advanced(by: x * 4 + 1).pointee = 0
lhsRowPixels.advanced(by: x * 4 + 2).pointee = 0
lhsRowPixels.advanced(by: x * 4 + 3).pointee = 255
}*/
deltaRowPixels.advanced(by: x * 4 + 0).pointee = 255
deltaRowPixels.advanced(by: x * 4 + 1).pointee = 0
deltaRowPixels.advanced(by: x * 4 + 2).pointee = 0
deltaRowPixels.advanced(by: x * 4 + 3).pointee = 255
foundDifferenceCount += 1
}
}
}
lhsBuffer.free()
rhsBuffer.free()
let colorSpace = Unmanaged<CGColorSpace>.passRetained(lhs.cgImage!.colorSpace!)
let deltaImage = try! deltaBuffer.createCGImage(format: vImage_CGImageFormat(bitsPerComponent: 8, bitsPerPixel: 32, colorSpace: colorSpace, bitmapInfo: lhs.cgImage!.bitmapInfo, version: 0, decode: nil, renderingIntent: .defaultIntent), flags: .doNotTile)
if foundDifferenceCount > maxDifferenceCount {
let colorSpace = Unmanaged<CGColorSpace>.passRetained(lhs.cgImage!.colorSpace!)
let diffImage = try! lhsBuffer.createCGImage(format: vImage_CGImageFormat(bitsPerComponent: 8, bitsPerPixel: 32, colorSpace: colorSpace, bitmapInfo: lhs.cgImage!.bitmapInfo, version: 0, decode: nil, renderingIntent: .defaultIntent), flags: .doNotTile)
return UIImage(cgImage: diffImage)
return (UIImage(cgImage: diffImage), UIImage(cgImage: deltaImage))
} else {
return nil
return (nil, UIImage(cgImage: deltaImage))
}
}
@available(iOS 13.0, *)
func processDrawAnimation(baseCachePath: String, path: String, name: String, size: CGSize, alwaysDraw: Bool, useNonReferenceRendering: Bool, updateImage: @escaping (UIImage?, UIImage?) -> Void) async -> Bool {
func processDrawAnimation(baseCachePath: String, path: String, name: String, size: CGSize, allowedDifference: Double, alwaysDraw: Bool, useNonReferenceRendering: Bool, updateImage: @escaping (UIImage?, UIImage?, UIImage?) -> Void) async -> Bool {
guard let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else {
print("Could not load \(path)")
return false
@ -84,17 +91,19 @@ func processDrawAnimation(baseCachePath: String, path: String, name: String, siz
let referenceImageData = try! Data(contentsOf: URL(fileURLWithPath: cacheFolderPath + "/frame\(frameIndex)"))
let referenceImage = decompressImageFrame(data: referenceImageData)
renderer.setFrame(frameIndex)
let image = renderer.render(for: size, useReferenceRendering: !useNonReferenceRendering)!
renderer.setFrame(CGFloat(frameIndex))
let image = renderer.render(for: size, useReferenceRendering: !useNonReferenceRendering, canUseMoreMemory: false, skipImageGeneration: false)!
if !useNonReferenceRendering, let diffImage = areImagesEqual(image, referenceImage) {
updateImage(diffImage, referenceImage)
let (diffImage, deltaImage) = areImagesEqual(image, referenceImage, allowedDifference: allowedDifference)
if !useNonReferenceRendering, let diffImage {
updateImage(diffImage, referenceImage, deltaImage)
print("Mismatch in frame \(frameIndex)")
return false
} else {
if alwaysDraw {
updateImage(image, referenceImage)
updateImage(image, referenceImage, diffImage)
}
return true
}
@ -279,6 +288,43 @@ func decompressImageFrame(data: Data) -> UIImage {
return decodeImageQOI(data)!
}
final class ReferenceLottieAnimationItem {
private let referenceAnimation: Animation
private let referenceLayer: MainThreadAnimationLayer
let frameCount: Int
init?(path: String) {
guard let referenceAnimation = Animation.filepath(path) else {
return nil
}
self.referenceAnimation = referenceAnimation
self.referenceLayer = MainThreadAnimationLayer(animation: referenceAnimation, imageProvider: BlankImageProvider(), textProvider: DefaultTextProvider(), fontProvider: DefaultFontProvider())
self.referenceLayer.position = referenceAnimation.bounds.center
self.referenceLayer.isOpaque = false
self.referenceLayer.backgroundColor = nil
self.frameCount = Int(referenceAnimation.endFrame - referenceAnimation.startFrame)
}
func setFrame(index: Int) {
self.referenceLayer.currentFrame = self.referenceAnimation.startFrame + CGFloat(index)
self.referenceLayer.displayUpdate()
}
func makeImage(width: Int, height: Int) -> UIImage? {
let size = CGSize(width: CGFloat(width), height: CGFloat(width))
let referenceContext = ImageContext(width: width, height: height)
referenceContext.context.clear(CGRect(origin: CGPoint(), size: size))
referenceContext.context.scaleBy(x: size.width / CGFloat(self.referenceAnimation.width), y: size.height / CGFloat(self.referenceAnimation.height))
referenceLayer.render(in: referenceContext.context)
return referenceContext.makeImage()
}
}
@MainActor
func cacheReferenceAnimation(baseCachePath: String, width: Int, path: String, name: String) -> String {
let targetFolderPath = cacheReferenceFolderPath(baseCachePath: baseCachePath, width: width, name: name)
@ -286,34 +332,19 @@ func cacheReferenceAnimation(baseCachePath: String, width: Int, path: String, na
return targetFolderPath
}
guard let referenceAnimation = Animation.filepath(path) else {
preconditionFailure("Could not parse reference animation at \(path)")
guard let referenceItem = ReferenceLottieAnimationItem(path: path) else {
preconditionFailure("Could not load reference animation at \(path)")
}
let referenceLayer = MainThreadAnimationLayer(animation: referenceAnimation, imageProvider: BlankImageProvider(), textProvider: DefaultTextProvider(), fontProvider: DefaultFontProvider())
let cacheFolderPath = NSTemporaryDirectory() + "\(UInt64.random(in: 0 ... UInt64.max))"
let _ = try? FileManager.default.createDirectory(atPath: cacheFolderPath, withIntermediateDirectories: true)
let frameCount = Int(referenceAnimation.endFrame - referenceAnimation.startFrame)
let size = CGSize(width: CGFloat(width), height: CGFloat(width))
for i in 0 ..< min(100000, frameCount) {
let frameIndex = i % frameCount
for i in 0 ..< min(100000, referenceItem.frameCount) {
let frameIndex = i % referenceItem.frameCount
referenceLayer.currentFrame = CGFloat(frameIndex)
referenceLayer.displayUpdate()
referenceLayer.position = referenceAnimation.bounds.center
referenceItem.setFrame(index: frameIndex)
referenceLayer.isOpaque = false
referenceLayer.backgroundColor = nil
let referenceContext = ImageContext(width: width, height: width)
referenceContext.context.clear(CGRect(origin: CGPoint(), size: size))
referenceContext.context.scaleBy(x: size.width / CGFloat(referenceAnimation.width), y: size.height / CGFloat(referenceAnimation.height))
referenceLayer.render(in: referenceContext.context)
let referenceImage = referenceContext.makeImage()
let referenceImage = referenceItem.makeImage(width: width, height: width)!
try! compressImageFrame(image: referenceImage).write(to: URL(fileURLWithPath: cacheFolderPath + "/frame\(i)"))
}

View file

@ -13,6 +13,7 @@ private final class ReferenceCompareTest {
private let view: UIView
private let imageView = UIImageView()
private let referenceImageView = UIImageView()
private let deltaImageView = UIImageView()
init(view: UIView, testNonReference: Bool) {
lottieSwift_getPathNativeBoundingBox = { path in
@ -37,6 +38,12 @@ private final class ReferenceCompareTest {
self.referenceImageView.backgroundColor = self.view.backgroundColor
self.referenceImageView.transform = CGAffineTransform.init(scaleX: 1.0, y: -1.0)
self.view.addSubview(self.deltaImageView)
self.deltaImageView.layer.magnificationFilter = .nearest
self.deltaImageView.frame = CGRect(origin: CGPoint(x: 10.0, y: topInset + 256.0 + 1.0 + 256.0 + 1.0), size: CGSize(width: 256.0, height: 256.0))
self.deltaImageView.backgroundColor = self.view.backgroundColor
self.deltaImageView.transform = CGAffineTransform.init(scaleX: 1.0, y: -1.0)
let bundlePath = Bundle.main.path(forResource: "TestDataBundle", ofType: "bundle")!
Task.detached {
@ -67,6 +74,9 @@ private final class ReferenceCompareTest {
"1391391008142393350.json": 1024
]
let allowedDifferences: [String: Double] = [
"1258816259754165.json": 0.04
]
let defaultSize = 128
let baseCachePath = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).path + "/frame-cache"
@ -78,7 +88,7 @@ private final class ReferenceCompareTest {
}
var continueFromName: String?
//continueFromName = "5089561049196134821.json"
//continueFromName = "1258816259754165.json"
let _ = await processAnimationFolderAsync(basePath: bundlePath, path: "", stopOnFailure: !testNonReference, process: { path, name, alwaysDraw in
if let continueFromNameValue = continueFromName {
@ -91,10 +101,11 @@ private final class ReferenceCompareTest {
let size = sizeMapping[name] ?? defaultSize
let result = await processDrawAnimation(baseCachePath: baseCachePath, path: path, name: name, size: CGSize(width: size, height: size), alwaysDraw: alwaysDraw, useNonReferenceRendering: testNonReference, updateImage: { image, referenceImage in
let result = await processDrawAnimation(baseCachePath: baseCachePath, path: path, name: name, size: CGSize(width: size, height: size), allowedDifference: allowedDifferences[name] ?? 0.01, alwaysDraw: alwaysDraw, useNonReferenceRendering: testNonReference, updateImage: { image, referenceImage, differenceImage in
DispatchQueue.main.async {
self.imageView.image = image
self.referenceImageView.image = referenceImage
self.deltaImageView.image = differenceImage
}
})
return result
@ -103,6 +114,139 @@ private final class ReferenceCompareTest {
}
}
@available(iOS 13.0, *)
private final class ManualReferenceCompareTest {
private final class Item {
let renderer: SoftwareLottieRenderer
let referenceRenderer: ReferenceLottieAnimationItem
init(renderer: SoftwareLottieRenderer, referenceRenderer: ReferenceLottieAnimationItem) {
self.renderer = renderer
self.referenceRenderer = referenceRenderer
}
}
private let view: UIView
private let imageView = UIImageView()
private let referenceImageView = UIImageView()
private let labelView = UILabel()
private let renderSize: CGSize
private let testNonReference: Bool
private let fileList: [(filePath: String, fileName: String)]
private var currentFileIndex: Int = 0
private var currentItem: Item?
private var frameDisplayLink: SharedDisplayLinkDriver.Link?
init(view: UIView) {
self.testNonReference = true
self.currentFileIndex = 0
lottieSwift_getPathNativeBoundingBox = { path in
return getPathNativeBoundingBox(path)
}
let bundlePath = Bundle.main.path(forResource: "TestDataBundle", ofType: "bundle")!
self.fileList = buildAnimationFolderItems(basePath: bundlePath, path: "")
self.renderSize = CGSize(width: 256.0, height: 256.0)
self.view = view
self.view.backgroundColor = .white
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
let topInset: CGFloat = 50.0
self.view.addSubview(self.imageView)
self.imageView.layer.magnificationFilter = .nearest
self.imageView.frame = CGRect(origin: CGPoint(x: 10.0, y: topInset), size: CGSize(width: 256.0, height: 256.0))
self.imageView.backgroundColor = self.view.backgroundColor
self.imageView.transform = CGAffineTransform.init(scaleX: 1.0, y: -1.0)
self.view.addSubview(self.referenceImageView)
self.referenceImageView.layer.magnificationFilter = .nearest
self.referenceImageView.frame = CGRect(origin: CGPoint(x: 10.0, y: topInset + 256.0 + 1.0), size: CGSize(width: 256.0, height: 256.0))
self.referenceImageView.backgroundColor = self.view.backgroundColor
self.referenceImageView.transform = CGAffineTransform.init(scaleX: 1.0, y: -1.0)
self.view.addSubview(self.labelView)
self.updateCurrentAnimation()
}
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state {
if recognizer.location(in: self.view).x <= self.view.bounds.width * 0.5 {
if self.currentFileIndex != 0 {
self.currentFileIndex = self.currentFileIndex - 1
}
} else {
self.currentFileIndex = (self.currentFileIndex + 1) % self.fileList.count
}
self.updateCurrentAnimation()
}
}
private func updateCurrentAnimation() {
self.imageView.image = nil
self.referenceImageView.image = nil
self.currentItem = nil
self.labelView.text = "\(self.currentFileIndex + 1) / \(self.fileList.count)"
self.labelView.sizeToFit()
self.labelView.center = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.height - 10.0 - self.labelView.bounds.height)
self.frameDisplayLink?.invalidate()
self.frameDisplayLink = nil
let (filePath, _) = self.fileList[self.currentFileIndex]
guard let data = try? Data(contentsOf: URL(fileURLWithPath: filePath)) else {
print("Could not load \(filePath)")
return
}
guard let renderer = SoftwareLottieRenderer(data: data) else {
print("Could not load animation at \(filePath)")
return
}
guard let referenceRenderer = ReferenceLottieAnimationItem(path: filePath) else {
print("Could not load reference animation at \(filePath)")
return
}
let currentItem = Item(renderer: renderer, referenceRenderer: referenceRenderer)
self.currentItem = currentItem
var animationTime = 0.0
let secondsPerFrame = 1.0 / Double(renderer.framesPerSecond)
let frameDisplayLink = SharedDisplayLinkDriver.shared.add(framesPerSecond: .max, { [weak self] deltaTime in
guard let self, let currentItem = self.currentItem else {
return
}
var frameIndex = animationTime / secondsPerFrame
frameIndex = frameIndex.truncatingRemainder(dividingBy: Double(currentItem.renderer.frameCount))
currentItem.renderer.setFrame(frameIndex)
let image = currentItem.renderer.render(for: self.renderSize, useReferenceRendering: !self.testNonReference, canUseMoreMemory: false, skipImageGeneration: false)!
self.imageView.image = image
currentItem.referenceRenderer.setFrame(index: Int(frameIndex))
let referenceImage = currentItem.referenceRenderer.makeImage(width: Int(self.renderSize.width), height: Int(self.renderSize.height))!
self.referenceImageView.image = referenceImage
animationTime += deltaTime
})
self.frameDisplayLink = frameDisplayLink
frameDisplayLink.isPaused = false
}
}
public final class ViewController: UIViewController {
private var link: SharedDisplayLinkDriver.Link?
private var test: AnyObject?
@ -115,13 +259,17 @@ public final class ViewController: UIViewController {
let bundlePath = Bundle.main.path(forResource: "TestDataBundle", ofType: "bundle")!
let filePath = bundlePath + "/fire.json"
let performanceFrameSize = 512
let performanceFrameSize = 128
self.view.layer.addSublayer(MetalEngine.shared.rootLayer)
if !"".isEmpty {
if #available(iOS 13.0, *) {
self.test = ReferenceCompareTest(view: self.view, testNonReference: true)
self.test = ReferenceCompareTest(view: self.view, testNonReference: false)
}
} else if "".isEmpty {
if #available(iOS 13.0, *) {
self.test = ManualReferenceCompareTest(view: self.view)
}
} else if !"".isEmpty {
/*let cachedAnimation = cacheLottieMetalAnimation(path: filePath)!
@ -160,8 +308,8 @@ public final class ViewController: UIViewController {
var numUpdates: Int = 0
var frameIndex = 0
while true {
animationRenderer.setFrame(frameIndex)
let _ = animationRenderer.render(for: CGSize(width: CGFloat(performanceFrameSize), height: CGFloat(performanceFrameSize)), useReferenceRendering: false)
animationRenderer.setFrame(CGFloat(frameIndex))
let _ = animationRenderer.render(for: CGSize(width: CGFloat(performanceFrameSize), height: CGFloat(performanceFrameSize)), useReferenceRendering: false, canUseMoreMemory: true, skipImageGeneration: true)
frameIndex = (frameIndex + 1) % animationRenderer.frameCount
numUpdates += 1
let timestamp = CFAbsoluteTimeGetCurrent()

View file

@ -3,12 +3,18 @@ load("@build_bazel_rules_apple//apple:apple.bzl",
"apple_dynamic_framework_import",
)
framework_imports = select({
"@build_bazel_rules_apple//apple:ios_arm64": glob([
"device/libskia.framework/**"
]),
"//build-system:ios_sim_arm64": glob([
"simulator/libskia.framework/**"
])
})
apple_dynamic_framework_import(
name = "libskia",
framework_imports = glob([
"libskia.framework/**"
]),
framework_imports = framework_imports,
visibility = ["//visibility:public"],
)

View file

@ -419,6 +419,8 @@ public protocol PresentationGroupCall: AnyObject {
var memberEvents: Signal<PresentationGroupCallMemberEvent, NoError> { get }
var reconnectedAsEvents: Signal<EnginePeer, NoError> { get }
var onMutedSpeechActivityDetected: ((Bool) -> Void)? { get set }
func toggleScheduledSubscription(_ subscribe: Bool)
func schedule(timestamp: Int32)
func startScheduled()

View file

@ -67,10 +67,10 @@ final class AttachmentTextInputActionButtonsNode: ASDisplayNode, ChatSendMessage
}
} else {
if highlighted {
let transition: Transition = .easeInOut(duration: 0.4)
let transition: ComponentTransition = .easeInOut(duration: 0.4)
transition.setScale(layer: strongSelf.sendContainerNode.layer, scale: 0.75)
} else {
let transition: Transition = .easeInOut(duration: 0.25)
let transition: ComponentTransition = .easeInOut(duration: 0.25)
transition.setScale(layer: strongSelf.sendContainerNode.layer, scale: 1.0)
}
}

View file

@ -79,7 +79,7 @@ private final class IconComponent: Component {
self.disposable?.dispose()
}
func update(component: IconComponent, availableSize: CGSize, transition: Transition) -> CGSize {
func update(component: IconComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
if self.component?.name != component.name || self.component?.fileReference?.media.fileId != component.fileReference?.media.fileId || self.component?.tintColor != component.tintColor {
if let fileReference = component.fileReference {
let previousName = self.component?.name ?? ""
@ -117,7 +117,7 @@ private final class IconComponent: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}
@ -1163,7 +1163,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
self.updateViews(transition: .init(animation: .curve(duration: 0.2, curve: .spring)))
}
func updateViews(transition: Transition) {
func updateViews(transition: ComponentTransition) {
guard let layout = self.validLayout else {
return
}

View file

@ -10,9 +10,11 @@ swift_library(
"-warnings-as-errors",
],
deps = [
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display",
"//submodules/LegacyComponents:LegacyComponents",
"//submodules/AsyncDisplayKit",
"//submodules/Display",
"//submodules/LegacyComponents",
"//submodules/MetalEngine",
"//submodules/TelegramUI/Components/Calls/CallScreen",
],
visibility = [
"//visibility:public",

View file

@ -3,6 +3,8 @@ import UIKit
import AsyncDisplayKit
import Display
import LegacyComponents
import CallScreen
import MetalEngine
public final class VoiceBlobNode: ASDisplayNode {
public init(
@ -36,9 +38,7 @@ public final class VoiceBlobNode: ASDisplayNode {
}
public final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDecoration {
private let smallBlob: BlobNode
private let mediumBlob: BlobNode
private let bigBlob: BlobNode
private let blobsLayer: CallBlobsLayer
private let maxLevel: CGFloat
@ -65,7 +65,7 @@ public final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDeco
) {
self.maxLevel = maxLevel
self.smallBlob = BlobNode(
/*self.smallBlob = BlobNode(
pointsCount: 8,
minRandomness: 0.1,
maxRandomness: 0.5,
@ -97,7 +97,9 @@ public final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDeco
maxScale: bigBlobRange.max,
scaleSpeed: 0.2,
isCircle: false
)
)*/
self.blobsLayer = CallBlobsLayer(colors: [UIColor.white, UIColor.white.withAlphaComponent(0.3), UIColor.white.withAlphaComponent(0.15)])
var updateInHierarchy: ((Bool) -> Void)?
self.hierarchyTrackingNode = HierarchyTrackingNode({ value in
@ -108,18 +110,21 @@ public final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDeco
self.addSubnode(self.hierarchyTrackingNode)
self.addSubnode(self.bigBlob)
/*self.addSubnode(self.bigBlob)
self.addSubnode(self.mediumBlob)
self.addSubnode(self.smallBlob)
self.addSubnode(self.smallBlob)*/
displayLinkAnimator = ConstantDisplayLinkAnimator() { [weak self] in
self.layer.addSublayer(self.blobsLayer)
self.displayLinkAnimator = ConstantDisplayLinkAnimator() { [weak self] in
guard let strongSelf = self else { return }
strongSelf.presentationAudioLevel = strongSelf.presentationAudioLevel * 0.9 + strongSelf.audioLevel * 0.1
strongSelf.updateAudioLevel()
strongSelf.smallBlob.level = strongSelf.presentationAudioLevel
/*strongSelf.smallBlob.level = strongSelf.presentationAudioLevel
strongSelf.mediumBlob.level = strongSelf.presentationAudioLevel
strongSelf.bigBlob.level = strongSelf.presentationAudioLevel
strongSelf.bigBlob.level = strongSelf.presentationAudioLevel*/
}
updateInHierarchy = { [weak self] value in
@ -138,12 +143,20 @@ public final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDeco
}
public func setColor(_ color: UIColor, animated: Bool) {
let transition: ContainedViewLayoutTransition
if animated {
transition = .animated(duration: 0.2, curve: .easeInOut)
} else {
transition = .immediate
}
transition.updateTintColor(layer: self.blobsLayer, color: color)
if let isManuallyInHierarchy = self.isManuallyInHierarchy, !isManuallyInHierarchy {
return
}
smallBlob.setColor(color, animated: animated)
/*smallBlob.setColor(color, animated: animated)
mediumBlob.setColor(color.withAlphaComponent(0.3), animated: animated)
bigBlob.setColor(color.withAlphaComponent(0.15), animated: animated)
bigBlob.setColor(color.withAlphaComponent(0.15), animated: animated)*/
}
public func updateLevel(_ level: CGFloat) {
@ -153,9 +166,9 @@ public final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDeco
public func updateLevel(_ level: CGFloat, immediately: Bool = false) {
let normalizedLevel = min(1, max(level / maxLevel, 0))
smallBlob.updateSpeedLevel(to: normalizedLevel)
/*smallBlob.updateSpeedLevel(to: normalizedLevel)
mediumBlob.updateSpeedLevel(to: normalizedLevel)
bigBlob.updateSpeedLevel(to: normalizedLevel)
bigBlob.updateSpeedLevel(to: normalizedLevel)*/
audioLevel = normalizedLevel
if immediately {
@ -163,6 +176,13 @@ public final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDeco
}
}
private func updateAudioLevel() {
let additionalAvatarScale = CGFloat(max(0.0, min(self.presentationAudioLevel * 18.0, 5.0)) * 0.05)
let blobAmplificationFactor: CGFloat = 2.0
let blobScale = 1.0 + additionalAvatarScale * blobAmplificationFactor
self.blobsLayer.transform = CATransform3DMakeScale(blobScale, blobScale, 1.0)
}
public func startAnimating() {
self.startAnimating(immediately: false)
}
@ -171,13 +191,13 @@ public final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDeco
guard !isAnimating else { return }
isAnimating = true
if !immediately {
/*if !immediately {
mediumBlob.layer.animateScale(from: 0.75, to: 1, duration: 0.35, removeOnCompletion: false)
bigBlob.layer.animateScale(from: 0.75, to: 1, duration: 0.35, removeOnCompletion: false)
} else {
mediumBlob.layer.removeAllAnimations()
bigBlob.layer.removeAllAnimations()
}
}*/
updateBlobsState()
@ -192,8 +212,8 @@ public final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDeco
guard isAnimating else { return }
isAnimating = false
mediumBlob.layer.animateScale(from: 1.0, to: 0.75, duration: duration, removeOnCompletion: false)
bigBlob.layer.animateScale(from: 1.0, to: 0.75, duration: duration, removeOnCompletion: false)
/*mediumBlob.layer.animateScale(from: 1.0, to: 0.75, duration: duration, removeOnCompletion: false)
bigBlob.layer.animateScale(from: 1.0, to: 0.75, duration: duration, removeOnCompletion: false)*/
updateBlobsState()
@ -201,7 +221,7 @@ public final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDeco
}
private func updateBlobsState() {
if self.isAnimating {
/*if self.isAnimating {
if self.smallBlob.frame.size != .zero {
smallBlob.startAnimating()
mediumBlob.startAnimating()
@ -211,15 +231,19 @@ public final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDeco
smallBlob.stopAnimating()
mediumBlob.stopAnimating()
bigBlob.stopAnimating()
}
}*/
}
override public func layoutSubviews() {
super.layoutSubviews()
self.smallBlob.frame = bounds
/*self.smallBlob.frame = bounds
self.mediumBlob.frame = bounds
self.bigBlob.frame = bounds
self.bigBlob.frame = bounds*/
let blobsFrame = bounds.insetBy(dx: floor(bounds.width * 0.12), dy: floor(bounds.height * 0.12))
self.blobsLayer.position = blobsFrame.center
self.blobsLayer.bounds = CGRect(origin: CGPoint(), size: blobsFrame.size)
self.updateBlobsState()
}

View file

@ -1192,7 +1192,7 @@ public final class AvatarNode: ASDisplayNode {
self.contentNode.setCustomLetters(letters, explicitColor: explicitColor, icon: icon)
}
public func setStoryStats(storyStats: StoryStats?, presentationParams: StoryPresentationParams, transition: Transition) {
public func setStoryStats(storyStats: StoryStats?, presentationParams: StoryPresentationParams, transition: ComponentTransition) {
if self.storyStats != storyStats || self.storyPresentationParams != presentationParams {
self.storyStats = storyStats
self.storyPresentationParams = presentationParams
@ -1242,7 +1242,7 @@ public final class AvatarNode: ASDisplayNode {
}
}
private func updateStoryIndicator(transition: Transition) {
private func updateStoryIndicator(transition: ComponentTransition) {
if !self.isNodeLoaded {
return
}

View file

@ -93,7 +93,7 @@ protocol BrowserContent: UIView {
func scrollToTop()
func updateLayout(size: CGSize, insets: UIEdgeInsets, transition: Transition)
func updateLayout(size: CGSize, insets: UIEdgeInsets, transition: ComponentTransition)
}
struct ContentScrollingUpdate {
@ -102,7 +102,7 @@ struct ContentScrollingUpdate {
public var absoluteOffsetToBottomEdge: CGFloat?
public var isReset: Bool
public var isInteracting: Bool
public var transition: Transition
public var transition: ComponentTransition
public init(
relativeOffset: CGFloat,
@ -110,7 +110,7 @@ struct ContentScrollingUpdate {
absoluteOffsetToBottomEdge: CGFloat?,
isReset: Bool,
isInteracting: Bool,
transition: Transition
transition: ComponentTransition
) {
self.relativeOffset = relativeOffset
self.absoluteOffsetToTopEdge = absoluteOffsetToTopEdge

View file

@ -873,7 +873,7 @@
//final class BrowserInstantPageContent: UIView, BrowserContent {
// var onScrollingUpdate: (ContentScrollingUpdate) -> Void
//
// func updateLayout(size: CGSize, insets: UIEdgeInsets, transition: ComponentFlow.Transition) {
// func updateLayout(size: CGSize, insets: UIEdgeInsets, transition: ComponentFlow.ComponentTransition) {
//
// }
//

View file

@ -289,7 +289,7 @@ private final class LoadingProgressComponent: Component {
preconditionFailure()
}
func update(component: LoadingProgressComponent, availableSize: CGSize, transition: Transition) -> CGSize {
func update(component: LoadingProgressComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
self.lineView.backgroundColor = component.color
let value = component.value
@ -306,14 +306,14 @@ private final class LoadingProgressComponent: Component {
self.currentValue = value
let transition: Transition
let transition: ComponentTransition
if animated && value > 0.0 {
transition = .spring(duration: 0.7)
} else {
transition = .immediate
}
let alphaTransition: Transition
let alphaTransition: ComponentTransition
if animated {
alphaTransition = .easeInOut(duration: 0.3)
} else {
@ -333,7 +333,7 @@ private final class LoadingProgressComponent: Component {
return View()
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}
@ -414,7 +414,7 @@ final class ReferenceButtonComponent: Component {
self.component?.action()
}
func update(component: ReferenceButtonComponent, availableSize: CGSize, transition: Transition) -> CGSize {
func update(component: ReferenceButtonComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
self.component = component
let componentSize = self.componentView.update(
@ -441,7 +441,7 @@ final class ReferenceButtonComponent: Component {
return View()
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -600,13 +600,13 @@ public class BrowserScreen: ViewController {
}
}
func requestLayout(transition: Transition) {
func requestLayout(transition: ComponentTransition) {
if let (layout, navigationBarHeight) = self.validLayout {
self.containerLayoutUpdated(layout: layout, navigationBarHeight: navigationBarHeight, transition: transition)
}
}
func containerLayoutUpdated(layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: Transition) {
func containerLayoutUpdated(layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ComponentTransition) {
self.validLayout = (layout, navigationBarHeight)
let environment = ViewControllerComponentContainer.Environment(
@ -705,7 +705,7 @@ public class BrowserScreen: ViewController {
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)
(self.displayNode as! Node).containerLayoutUpdated(layout: layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.height, transition: Transition(transition))
(self.displayNode as! Node).containerLayoutUpdated(layout: layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.height, transition: ComponentTransition(transition))
}
}

View file

@ -240,7 +240,7 @@ final class SearchBarContentComponent: Component {
}
}
func update(component: SearchBarContentComponent, availableSize: CGSize, transition: Transition) -> CGSize {
func update(component: SearchBarContentComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
self.component = component
self.update(theme: component.theme, strings: component.strings, size: availableSize, transition: transition)
@ -249,7 +249,7 @@ final class SearchBarContentComponent: Component {
return availableSize
}
public func update(theme: PresentationTheme, strings: PresentationStrings, size: CGSize, transition: Transition) {
public func update(theme: PresentationTheme, strings: PresentationStrings, size: CGSize, transition: ComponentTransition) {
let params = Params(
theme: theme,
strings: strings,
@ -351,7 +351,7 @@ final class SearchBarContentComponent: Component {
return View()
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -100,10 +100,10 @@ final class BrowserToolbarComponent: CombinedComponent {
if let centerItem = item {
context.add(centerItem
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentHeight / 2.0 + offset))
.appear(Transition.Appear({ _, view, transition in
.appear(ComponentTransition.Appear({ _, view, transition in
transition.animatePosition(view: view, from: CGPoint(x: 0.0, y: size.height), to: .zero, additive: true)
}))
.disappear(Transition.Disappear({ view, transition, completion in
.disappear(ComponentTransition.Disappear({ view, transition, completion in
transition.animatePosition(view: view, from: .zero, to: CGPoint(x: 0.0, y: size.height), additive: true, completion: { _ in
completion()
})

View file

@ -258,7 +258,7 @@ final class BrowserWebContent: UIView, BrowserContent, UIScrollViewDelegate {
self.webView.scrollView.setContentOffset(CGPoint(x: 0.0, y: -self.webView.scrollView.contentInset.top), animated: true)
}
func updateLayout(size: CGSize, insets: UIEdgeInsets, transition: Transition) {
func updateLayout(size: CGSize, insets: UIEdgeInsets, transition: ComponentTransition) {
var scrollInsets = insets
scrollInsets.top = 0.0
if self.webView.scrollView.contentInset != insets {
@ -303,7 +303,7 @@ final class BrowserWebContent: UIView, BrowserContent, UIScrollViewDelegate {
}
private func snapScrollingOffsetToInsets() {
let transition = Transition(animation: .curve(duration: 0.4, curve: .spring))
let transition = ComponentTransition(animation: .curve(duration: 0.4, curve: .spring))
self.updateScrollingOffset(isReset: false, transition: transition)
}
@ -317,7 +317,7 @@ final class BrowserWebContent: UIView, BrowserContent, UIScrollViewDelegate {
self.snapScrollingOffsetToInsets()
}
private func updateScrollingOffset(isReset: Bool, transition: Transition) {
private func updateScrollingOffset(isReset: Bool, transition: ComponentTransition) {
let scrollView = self.webView.scrollView
let isInteracting = scrollView.isDragging || scrollView.isDecelerating
if let previousScrollingOffsetValue = self.previousScrollingOffset {

View file

@ -404,7 +404,7 @@ private final class DayComponent: Component {
self.action?()
}
func update(component: DayComponent, availableSize: CGSize, environment: Environment<DayEnvironment>, transition: Transition) -> CGSize {
func update(component: DayComponent, availableSize: CGSize, environment: Environment<DayEnvironment>, transition: ComponentTransition) -> CGSize {
let isFirstTime = self.action == nil
self.action = component.action
@ -613,7 +613,7 @@ private final class DayComponent: Component {
return View()
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<DayEnvironment>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<DayEnvironment>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, environment: environment, transition: transition)
}
}
@ -859,7 +859,7 @@ private final class MonthComponent: CombinedComponent {
let delayIndex = dayEnvironment.selectionDelayCoordination
context.add(selection
.position(CGPoint(x: selectionRect.midX, y: selectionRect.midY))
.appear(Transition.Appear { _, view, transition in
.appear(ComponentTransition.Appear { _, view, transition in
if case .none = transition.animation {
return
}
@ -867,7 +867,7 @@ private final class MonthComponent: CombinedComponent {
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.05, delay: delay)
view.layer.animateFrame(from: CGRect(origin: view.frame.origin, size: CGSize(width: selectionRadius, height: view.frame.height)), to: view.frame, duration: 0.25, delay: delay, timingFunction: kCAMediaTimingFunctionSpring)
})
.disappear(Transition.Disappear { view, transition, completion in
.disappear(ComponentTransition.Disappear { view, transition, completion in
if case .none = transition.animation {
completion()
return
@ -1203,12 +1203,12 @@ public final class CalendarMessageScreen: ViewController {
}
func toggleSelectionMode() {
var transition: Transition = .immediate
var transition: ComponentTransition = .immediate
if self.selectionState == nil {
self.selectionState = SelectionState(dayRange: nil)
} else {
self.selectionState = nil
transition = Transition(animation: .curve(duration: 0.25, curve: .easeInOut))
transition = ComponentTransition(animation: .curve(duration: 0.25, curve: .easeInOut))
transition = transition.withUserData(SelectionTransition.end)
}
@ -1236,7 +1236,7 @@ public final class CalendarMessageScreen: ViewController {
self.selectionToolbarActionSelected()
}
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition, componentsTransition: Transition) {
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition, componentsTransition: ComponentTransition) {
let isFirstLayout = self.validLayout == nil
self.validLayout = (layout, navigationHeight)
@ -1614,7 +1614,7 @@ public final class CalendarMessageScreen: ViewController {
return true
}
func updateMonthViews(transition: Transition) {
func updateMonthViews(transition: ComponentTransition) {
guard let (width, _, frames) = self.scrollLayout else {
return
}
@ -1657,7 +1657,7 @@ public final class CalendarMessageScreen: ViewController {
return
}
if var selectionState = strongSelf.selectionState {
var transition = Transition(animation: .curve(duration: 0.2, curve: .spring))
var transition = ComponentTransition(animation: .curve(duration: 0.2, curve: .spring))
if let dayRange = selectionState.dayRange {
if dayRange.lowerBound == timestamp || dayRange.upperBound == timestamp {
selectionState.dayRange = nil
@ -1712,7 +1712,7 @@ public final class CalendarMessageScreen: ViewController {
guard var selectionState = strongSelf.selectionState else {
return
}
var transition = Transition(animation: .curve(duration: 0.2, curve: .spring))
var transition = ComponentTransition(animation: .curve(duration: 0.2, curve: .spring))
if let dayRange = selectionState.dayRange {
if dayRange == range {
selectionState.dayRange = nil
@ -1751,7 +1751,7 @@ public final class CalendarMessageScreen: ViewController {
}
}
private func updateSelectionState(transition: Transition) {
private func updateSelectionState(transition: ComponentTransition) {
var title = self.presentationData.strings.MessageCalendar_Title
if let selectionState = self.selectionState, let dayRange = selectionState.dayRange {
var selectedCount = 0

View file

@ -303,7 +303,7 @@ final class ChatListContainerItemNode: ASDisplayNode {
if let chatFolderUpdates = self.chatFolderUpdates {
let topPanel: TopPanelItem
var topPanelTransition = Transition(transition)
var topPanelTransition = ComponentTransition(transition)
if let current = self.topPanel {
topPanel = current
} else {
@ -350,7 +350,7 @@ final class ChatListContainerItemNode: ASDisplayNode {
additionalTopInset += topPanelHeight
} else if self.canReportPeer {
let topPanel: TopPanelItem
var topPanelTransition = Transition(transition)
var topPanelTransition = ComponentTransition(transition)
if let current = self.topPanel {
topPanel = current
} else {

View file

@ -898,7 +898,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
return
}
self.chatListDisplayNode.requestNavigationBarLayout(transition: Transition.immediate.withUserData(ChatListNavigationBar.AnimationHint(
self.chatListDisplayNode.requestNavigationBarLayout(transition: ComponentTransition.immediate.withUserData(ChatListNavigationBar.AnimationHint(
disableStoriesAnimations: false,
crossfadeStoryPeers: true
)))

View file

@ -1302,7 +1302,7 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
}
}
private func updateNavigationBar(layout: ContainerViewLayout, deferScrollApplication: Bool, transition: Transition) -> (navigationHeight: CGFloat, storiesInset: CGFloat) {
private func updateNavigationBar(layout: ContainerViewLayout, deferScrollApplication: Bool, transition: ComponentTransition) -> (navigationHeight: CGFloat, storiesInset: CGFloat) {
let headerContent = self.controller?.updateHeaderContent()
var tabsNode: ASDisplayNode?
@ -1445,7 +1445,7 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
}
if let navigationBarComponentView = self.navigationBarView.view as? ChatListNavigationBar.View {
navigationBarComponentView.applyScroll(offset: offset, allowAvatarsExpansion: allowAvatarsExpansion, forceUpdate: false, transition: Transition(transition).withUserData(ChatListNavigationBar.AnimationHint(
navigationBarComponentView.applyScroll(offset: offset, allowAvatarsExpansion: allowAvatarsExpansion, forceUpdate: false, transition: ComponentTransition(transition).withUserData(ChatListNavigationBar.AnimationHint(
disableStoriesAnimations: self.tempDisableStoriesAnimations,
crossfadeStoryPeers: false
)))
@ -1460,7 +1460,7 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
transition.updateSublayerTransformOffset(layer: self.mainContainerNode.layer, offset: CGPoint(x: 0.0, y: -mainDelta))
}
func requestNavigationBarLayout(transition: Transition) {
func requestNavigationBarLayout(transition: ComponentTransition) {
guard let (layout, _, _, _, _) = self.containerLayout else {
return
}
@ -1491,7 +1491,7 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
var cleanNavigationBarHeight = cleanNavigationBarHeight
var storiesInset = storiesInset
let navigationBarLayout = self.updateNavigationBar(layout: layout, deferScrollApplication: true, transition: Transition(transition))
let navigationBarLayout = self.updateNavigationBar(layout: layout, deferScrollApplication: true, transition: ComponentTransition(transition))
self.mainContainerNode.initialScrollingOffset = ChatListNavigationBar.searchScrollHeight + navigationBarLayout.storiesInset
navigationBarHeight = navigationBarLayout.navigationHeight
@ -1613,7 +1613,7 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
if let navigationBarComponentView = self.navigationBarView.view as? ChatListNavigationBar.View {
navigationBarComponentView.deferScrollApplication = false
navigationBarComponentView.applyCurrentScroll(transition: Transition(transition))
navigationBarComponentView.applyCurrentScroll(transition: ComponentTransition(transition))
}
}
@ -1714,7 +1714,7 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
func willScrollToTop() {
if let navigationBarComponentView = self.navigationBarView.view as? ChatListNavigationBar.View {
navigationBarComponentView.applyScroll(offset: 0.0, allowAvatarsExpansion: false, transition: Transition(animation: .curve(duration: 0.3, curve: .slide)))
navigationBarComponentView.applyScroll(offset: 0.0, allowAvatarsExpansion: false, transition: ComponentTransition(animation: .curve(duration: 0.3, curve: .slide)))
}
}

View file

@ -316,7 +316,7 @@ final class ChatListEmptyNode: ASDisplayNode {
self.emptyArchive = emptyArchive
}
let emptyArchiveSize = emptyArchive.update(
transition: Transition(transition),
transition: ComponentTransition(transition),
component: AnyComponent(ArchiveInfoContentComponent(
theme: self.theme,
strings: self.strings,

View file

@ -318,7 +318,7 @@ private final class ChatListItemTagListComponent: Component {
preconditionFailure()
}
func update(component: ChatListItemTagListComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(component: ChatListItemTagListComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
var validIds: [Int32] = []
let spacing: CGFloat = floorToScreenPixels(5.0 * component.sizeFactor)
var nextX: CGFloat = 0.0
@ -387,7 +387,7 @@ private final class ChatListItemTagListComponent: Component {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -1265,7 +1265,15 @@ public func canSendMessagesToChat(_ state: ChatPresentationInterfaceState) -> Bo
return false
}
} else if case .customChatContents = state.chatLocation {
return true
if case let .customChatContents(contents) = state.subject {
if case .hashTagSearch = contents.kind {
return false
} else {
return true
}
} else {
return true
}
} else {
return false
}

View file

@ -44,10 +44,10 @@ public protocol ChatSendMessageContextScreenMediaPreview: AnyObject {
var globalClippingRect: CGRect? { get }
var layoutType: ChatSendMessageContextScreenMediaPreviewLayoutType { get }
func animateIn(transition: Transition)
func animateOut(transition: Transition)
func animateOutOnSend(transition: Transition)
func update(containerSize: CGSize, transition: Transition) -> CGSize
func animateIn(transition: ComponentTransition)
func animateOut(transition: ComponentTransition)
func animateOutOnSend(transition: ComponentTransition)
func update(containerSize: CGSize, transition: ComponentTransition) -> CGSize
}
final class ChatSendMessageContextScreenComponent: Component {
@ -270,7 +270,7 @@ final class ChatSendMessageContextScreenComponent: Component {
return false
}
func update(component: ChatSendMessageContextScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
func update(component: ChatSendMessageContextScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
self.isUpdating = true
defer {
self.isUpdating = false
@ -308,7 +308,7 @@ final class ChatSendMessageContextScreenComponent: Component {
let messageActionsSpacing: CGFloat = 7.0
let alphaTransition: Transition
let alphaTransition: ComponentTransition
if transition.animation.isImmediate {
alphaTransition = .immediate
} else {
@ -617,7 +617,7 @@ final class ChatSendMessageContextScreenComponent: Component {
return
}
if !self.isUpdating {
self.state?.updated(transition: Transition(transition))
self.state?.updated(transition: ComponentTransition(transition))
}
}
)
@ -775,7 +775,7 @@ final class ChatSendMessageContextScreenComponent: Component {
return
}
if !self.isUpdating {
self.state?.updated(transition: Transition(transition))
self.state?.updated(transition: ComponentTransition(transition))
}
},
requestLayout: { [weak self] transition in
@ -783,7 +783,7 @@ final class ChatSendMessageContextScreenComponent: Component {
return
}
if !self.isUpdating {
self.state?.updated(transition: Transition(transition))
self.state?.updated(transition: ComponentTransition(transition))
}
},
requestUpdateOverlayWantsToBeBelowKeyboard: { [weak self] transition in
@ -1167,7 +1167,7 @@ final class ChatSendMessageContextScreenComponent: Component {
break
case .animatedIn:
transition.setAlpha(view: actionsStackNode.view, alpha: 1.0)
Transition.immediate.setScale(view: actionsStackNode.view, scale: 1.0)
ComponentTransition.immediate.setScale(view: actionsStackNode.view, scale: 1.0)
actionsStackNode.layer.animateSpring(from: 0.001 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.42, damping: 104.0)
messageItemView.animateIn(
@ -1340,7 +1340,7 @@ final class ChatSendMessageContextScreenComponent: Component {
return View()
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -59,7 +59,7 @@ public final class ChatSendMessageScreenEffectIcon: Component {
fatalError("init(coder:) has not been implemented")
}
func update(component: ChatSendMessageScreenEffectIcon, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(component: ChatSendMessageScreenEffectIcon, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
if case let .file(file) = component.content {
let fileView: ReactionIconView
if let current = self.fileView {
@ -130,7 +130,7 @@ public final class ChatSendMessageScreenEffectIcon: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
@ -246,7 +246,7 @@ final class MessageItemView: UIView {
func animateIn(
sourceTextInputView: ChatInputTextView?,
isEditMessage: Bool,
transition: Transition
transition: ComponentTransition
) {
if isEditMessage {
transition.animateScale(view: self, from: 0.001, to: 1.0)
@ -262,7 +262,7 @@ final class MessageItemView: UIView {
sourceTextInputView: ChatInputTextView?,
toEmpty: Bool,
isEditMessage: Bool,
transition: Transition
transition: ComponentTransition
) {
if isEditMessage {
transition.setScale(view: self, scale: 0.001)
@ -294,7 +294,7 @@ final class MessageItemView: UIView {
containerSize: CGSize,
effect: AvailableMessageEffects.MessageEffect?,
isEditMessage: Bool,
transition: Transition
transition: ComponentTransition
) -> CGSize {
self.emojiViewProvider = emojiViewProvider
@ -351,7 +351,7 @@ final class MessageItemView: UIView {
backgroundNode: backgroundNode
)
let alphaTransition: Transition = transition.animation.isImmediate ? .immediate : .easeInOut(duration: 0.25)
let alphaTransition: ComponentTransition = transition.animation.isImmediate ? .immediate : .easeInOut(duration: 0.25)
if let sourceMediaPreview {
let mediaPreviewClippingView: UIView
@ -764,7 +764,7 @@ final class MessageItemView: UIView {
isAnimatedIn: Bool,
localFrame: CGRect,
containerSize: CGSize,
transition: Transition
transition: ComponentTransition
) {
if let mediaPreviewClippingView = self.mediaPreviewClippingView, let sourceMediaPreview {
let clippingFrame: CGRect

View file

@ -67,7 +67,7 @@ final class SendButton: HighlightTrackingButton {
isAnimatedIn: Bool,
isLoadingEffectAnimation: Bool,
size: CGSize,
transition: Transition
transition: ComponentTransition
) {
let innerSize = CGSize(width: size.width - 5.5 * 2.0, height: 33.0)
let containerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - innerSize.width) * 0.5), y: floorToScreenPixels((size.height - innerSize.height) * 0.5)), size: innerSize)
@ -197,7 +197,7 @@ final class SendButton: HighlightTrackingButton {
}
}
func updateGlobalRect(rect: CGRect, within containerSize: CGSize, transition: Transition) {
func updateGlobalRect(rect: CGRect, within containerSize: CGSize, transition: ComponentTransition) {
if let backgroundContent = self.backgroundContent {
backgroundContent.update(rect: CGRect(origin: CGPoint(x: rect.minX + self.containerView.frame.minX, y: rect.minY + self.containerView.frame.minY), size: backgroundContent.bounds.size), within: containerSize, transition: transition.containedViewLayoutTransition)
}

View file

@ -1,9 +1,9 @@
import Foundation
import UIKit
public extension Transition.Appear {
static func `default`(scale: Bool = false, alpha: Bool = false) -> Transition.Appear {
return Transition.Appear { component, view, transition in
public extension ComponentTransition.Appear {
static func `default`(scale: Bool = false, alpha: Bool = false) -> ComponentTransition.Appear {
return ComponentTransition.Appear { component, view, transition in
if scale {
transition.animateScale(view: view, from: 0.01, to: 1.0)
}
@ -13,16 +13,16 @@ public extension Transition.Appear {
}
}
static func scaleIn() -> Transition.Appear {
return Transition.Appear { component, view, transition in
static func scaleIn() -> ComponentTransition.Appear {
return ComponentTransition.Appear { component, view, transition in
transition.animateScale(view: view, from: 0.01, to: 1.0)
}
}
}
public extension Transition.AppearWithGuide {
static func `default`(scale: Bool = false, alpha: Bool = false) -> Transition.AppearWithGuide {
return Transition.AppearWithGuide { component, view, guide, transition in
public extension ComponentTransition.AppearWithGuide {
static func `default`(scale: Bool = false, alpha: Bool = false) -> ComponentTransition.AppearWithGuide {
return ComponentTransition.AppearWithGuide { component, view, guide, transition in
if scale {
transition.animateScale(view: view, from: 0.01, to: 1.0)
}
@ -34,9 +34,9 @@ public extension Transition.AppearWithGuide {
}
}
public extension Transition.Disappear {
static func `default`(scale: Bool = false, alpha: Bool = true) -> Transition.Disappear {
return Transition.Disappear { view, transition, completion in
public extension ComponentTransition.Disappear {
static func `default`(scale: Bool = false, alpha: Bool = true) -> ComponentTransition.Disappear {
return ComponentTransition.Disappear { view, transition, completion in
if scale {
transition.setScale(view: view, scale: 0.01, completion: { _ in
if !alpha {
@ -56,9 +56,9 @@ public extension Transition.Disappear {
}
}
public extension Transition.DisappearWithGuide {
static func `default`(alpha: Bool = true) -> Transition.DisappearWithGuide {
return Transition.DisappearWithGuide { stage, view, guide, transition, completion in
public extension ComponentTransition.DisappearWithGuide {
static func `default`(alpha: Bool = true) -> ComponentTransition.DisappearWithGuide {
return ComponentTransition.DisappearWithGuide { stage, view, guide, transition, completion in
switch stage {
case .begin:
if alpha {
@ -78,8 +78,8 @@ public extension Transition.DisappearWithGuide {
}
}
public extension Transition.Update {
static let `default` = Transition.Update { component, view, transition in
public extension ComponentTransition.Update {
static let `default` = ComponentTransition.Update { component, view, transition in
let frame = component.size.centered(around: component._position ?? CGPoint())
if let scale = component._scale {
transition.setBounds(view: view, bounds: CGRect(origin: CGPoint(), size: frame.size))

View file

@ -6,7 +6,7 @@ private func updateChildAnyComponent<EnvironmentType>(
component: AnyComponent<EnvironmentType>,
view: UIView,
availableSize: CGSize,
transition: Transition
transition: ComponentTransition
) -> _UpdatedChildComponent {
let parentContext = _AnyCombinedComponentContext.current
@ -85,7 +85,7 @@ public final class _ConcreteChildComponent<ComponentType: Component>: _AnyChildC
return .direct(self.directId)
}
public func update(component: ComponentType, @EnvironmentBuilder environment: () -> Environment<ComponentType.EnvironmentType>, availableSize: CGSize, transition: Transition) -> _UpdatedChildComponent {
public func update(component: ComponentType, @EnvironmentBuilder environment: () -> Environment<ComponentType.EnvironmentType>, availableSize: CGSize, transition: ComponentTransition) -> _UpdatedChildComponent {
let parentContext = _AnyCombinedComponentContext.current
if !parentContext.updateContext.configuredViews.insert(self.id).inserted {
preconditionFailure("Child component can only be configured once")
@ -119,7 +119,7 @@ public final class _ConcreteChildComponent<ComponentType: Component>: _AnyChildC
}
public extension _ConcreteChildComponent where ComponentType.EnvironmentType == Empty {
func update(component: ComponentType, availableSize: CGSize, transition: Transition) -> _UpdatedChildComponent {
func update(component: ComponentType, availableSize: CGSize, transition: ComponentTransition) -> _UpdatedChildComponent {
return self.update(component: component, environment: {}, availableSize: availableSize, transition: transition)
}
}
@ -141,7 +141,7 @@ public final class _ChildComponentGuide {
return .direct(self.directId)
}
public func update(position: CGPoint, transition: Transition) -> _UpdatedChildComponentGuide {
public func update(position: CGPoint, transition: ComponentTransition) -> _UpdatedChildComponentGuide {
let parentContext = _AnyCombinedComponentContext.current
let previousPosition = parentContext.guides[self.id]
@ -182,11 +182,11 @@ public final class _UpdatedChildComponent {
var _clipsToBounds: Bool?
var _shadow: Shadow?
fileprivate var transitionAppear: Transition.Appear?
fileprivate var transitionAppearWithGuide: (Transition.AppearWithGuide, _AnyChildComponent.Id)?
fileprivate var transitionDisappear: Transition.Disappear?
fileprivate var transitionDisappearWithGuide: (Transition.DisappearWithGuide, _AnyChildComponent.Id)?
fileprivate var transitionUpdate: Transition.Update?
fileprivate var transitionAppear: ComponentTransition.Appear?
fileprivate var transitionAppearWithGuide: (ComponentTransition.AppearWithGuide, _AnyChildComponent.Id)?
fileprivate var transitionDisappear: ComponentTransition.Disappear?
fileprivate var transitionDisappearWithGuide: (ComponentTransition.DisappearWithGuide, _AnyChildComponent.Id)?
fileprivate var transitionUpdate: ComponentTransition.Update?
fileprivate var gestures: [Gesture] = []
fileprivate init(
@ -203,31 +203,31 @@ public final class _UpdatedChildComponent {
self.size = size
}
@discardableResult public func appear(_ transition: Transition.Appear) -> _UpdatedChildComponent {
@discardableResult public func appear(_ transition: ComponentTransition.Appear) -> _UpdatedChildComponent {
self.transitionAppear = transition
self.transitionAppearWithGuide = nil
return self
}
@discardableResult public func appear(_ transition: Transition.AppearWithGuide, guide: _UpdatedChildComponentGuide) -> _UpdatedChildComponent {
@discardableResult public func appear(_ transition: ComponentTransition.AppearWithGuide, guide: _UpdatedChildComponentGuide) -> _UpdatedChildComponent {
self.transitionAppear = nil
self.transitionAppearWithGuide = (transition, guide.instance.id)
return self
}
@discardableResult public func disappear(_ transition: Transition.Disappear) -> _UpdatedChildComponent {
@discardableResult public func disappear(_ transition: ComponentTransition.Disappear) -> _UpdatedChildComponent {
self.transitionDisappear = transition
self.transitionDisappearWithGuide = nil
return self
}
@discardableResult public func disappear(_ transition: Transition.DisappearWithGuide, guide: _UpdatedChildComponentGuide) -> _UpdatedChildComponent {
@discardableResult public func disappear(_ transition: ComponentTransition.DisappearWithGuide, guide: _UpdatedChildComponentGuide) -> _UpdatedChildComponent {
self.transitionDisappear = nil
self.transitionDisappearWithGuide = (transition, guide.instance.id)
return self
}
@discardableResult public func update(_ transition: Transition.Update) -> _UpdatedChildComponent {
@discardableResult public func update(_ transition: ComponentTransition.Update) -> _UpdatedChildComponent {
self.transitionUpdate = transition
return self
}
@ -278,7 +278,7 @@ public final class _EnvironmentChildComponent<EnvironmentType>: _AnyChildCompone
return .direct(self.directId)
}
func update(component: AnyComponent<EnvironmentType>, @EnvironmentBuilder environment: () -> Environment<EnvironmentType>, availableSize: CGSize, transition: Transition) -> _UpdatedChildComponent {
func update(component: AnyComponent<EnvironmentType>, @EnvironmentBuilder environment: () -> Environment<EnvironmentType>, availableSize: CGSize, transition: ComponentTransition) -> _UpdatedChildComponent {
let parentContext = _AnyCombinedComponentContext.current
if !parentContext.updateContext.configuredViews.insert(self.id).inserted {
preconditionFailure("Child component can only be configured once")
@ -312,17 +312,17 @@ public final class _EnvironmentChildComponent<EnvironmentType>: _AnyChildCompone
}
public extension _EnvironmentChildComponent where EnvironmentType == Empty {
func update(component: AnyComponent<EnvironmentType>, availableSize: CGSize, transition: Transition) -> _UpdatedChildComponent {
func update(component: AnyComponent<EnvironmentType>, availableSize: CGSize, transition: ComponentTransition) -> _UpdatedChildComponent {
return self.update(component: component, environment: {}, availableSize: availableSize, transition: transition)
}
}
public extension _EnvironmentChildComponent {
func update<ComponentType: Component>(_ component: ComponentType, @EnvironmentBuilder environment: () -> Environment<EnvironmentType>, availableSize: CGSize, transition: Transition) -> _UpdatedChildComponent where ComponentType.EnvironmentType == EnvironmentType {
func update<ComponentType: Component>(_ component: ComponentType, @EnvironmentBuilder environment: () -> Environment<EnvironmentType>, availableSize: CGSize, transition: ComponentTransition) -> _UpdatedChildComponent where ComponentType.EnvironmentType == EnvironmentType {
return self.update(component: AnyComponent(component), environment: environment, availableSize: availableSize, transition: transition)
}
func update<ComponentType: Component>(_ component: ComponentType, @EnvironmentBuilder environment: () -> Environment<EnvironmentType>, availableSize: CGSize, transition: Transition) -> _UpdatedChildComponent where ComponentType.EnvironmentType == EnvironmentType, EnvironmentType == Empty {
func update<ComponentType: Component>(_ component: ComponentType, @EnvironmentBuilder environment: () -> Environment<EnvironmentType>, availableSize: CGSize, transition: ComponentTransition) -> _UpdatedChildComponent where ComponentType.EnvironmentType == EnvironmentType, EnvironmentType == Empty {
return self.update(component: AnyComponent(component), environment: {}, availableSize: availableSize, transition: transition)
}
}
@ -334,7 +334,7 @@ public final class _EnvironmentChildComponentFromMap<EnvironmentType>: _AnyChild
self.id = id
}
public func update(component: AnyComponent<EnvironmentType>, @EnvironmentBuilder environment: () -> Environment<EnvironmentType>, availableSize: CGSize, transition: Transition) -> _UpdatedChildComponent {
public func update(component: AnyComponent<EnvironmentType>, @EnvironmentBuilder environment: () -> Environment<EnvironmentType>, availableSize: CGSize, transition: ComponentTransition) -> _UpdatedChildComponent {
let parentContext = _AnyCombinedComponentContext.current
if !parentContext.updateContext.configuredViews.insert(self.id).inserted {
preconditionFailure("Child component can only be configured once")
@ -368,7 +368,7 @@ public final class _EnvironmentChildComponentFromMap<EnvironmentType>: _AnyChild
}
public extension _EnvironmentChildComponentFromMap where EnvironmentType == Empty {
func update(component: AnyComponent<EnvironmentType>, availableSize: CGSize, transition: Transition) -> _UpdatedChildComponent {
func update(component: AnyComponent<EnvironmentType>, availableSize: CGSize, transition: ComponentTransition) -> _UpdatedChildComponent {
return self.update(component: component, environment: {}, availableSize: availableSize, transition: transition)
}
}
@ -393,7 +393,7 @@ public final class CombinedComponentContext<ComponentType: Component> {
public let component: ComponentType
public let availableSize: CGSize
public let transition: Transition
public let transition: ComponentTransition
private let addImpl: (_ updatedComponent: _UpdatedChildComponent) -> Void
public var environment: Environment<ComponentType.EnvironmentType> {
@ -408,7 +408,7 @@ public final class CombinedComponentContext<ComponentType: Component> {
view: UIView,
component: ComponentType,
availableSize: CGSize,
transition: Transition,
transition: ComponentTransition,
add: @escaping (_ updatedComponent: _UpdatedChildComponent) -> Void
) {
self.context = context
@ -467,8 +467,8 @@ private class _AnyCombinedComponentContext {
class ChildView {
let view: UIView
var index: Int
var transition: Transition.Disappear?
var transitionWithGuide: (Transition.DisappearWithGuide, _AnyChildComponent.Id)?
var transition: ComponentTransition.Disappear?
var transitionWithGuide: (ComponentTransition.DisappearWithGuide, _AnyChildComponent.Id)?
var gestures: [UInt: UIGestureRecognizer] = [:]
@ -507,15 +507,15 @@ private class _AnyCombinedComponentContext {
class DisappearingChildView {
let view: UIView
let guideId: _AnyChildComponent.Id?
let transition: Transition.Disappear?
let transitionWithGuide: Transition.DisappearWithGuide?
let transition: ComponentTransition.Disappear?
let transitionWithGuide: ComponentTransition.DisappearWithGuide?
let completion: () -> Void
init(
view: UIView,
guideId: _AnyChildComponent.Id?,
transition: Transition.Disappear?,
transitionWithGuide: Transition.DisappearWithGuide?,
transition: ComponentTransition.Disappear?,
transitionWithGuide: ComponentTransition.DisappearWithGuide?,
completion: @escaping () -> Void
) {
self.view = view
@ -555,39 +555,39 @@ private extension UIView {
}
}
public extension Transition {
public extension ComponentTransition {
final class Appear {
private let f: (_UpdatedChildComponent, UIView, Transition) -> Void
private let f: (_UpdatedChildComponent, UIView, ComponentTransition) -> Void
public init(_ f: @escaping (_UpdatedChildComponent, UIView, Transition) -> Void) {
public init(_ f: @escaping (_UpdatedChildComponent, UIView, ComponentTransition) -> Void) {
self.f = f
}
public func callAsFunction(component: _UpdatedChildComponent, view: UIView, transition: Transition) {
public func callAsFunction(component: _UpdatedChildComponent, view: UIView, transition: ComponentTransition) {
self.f(component, view, transition)
}
}
final class AppearWithGuide {
private let f: (_UpdatedChildComponent, UIView, CGPoint, Transition) -> Void
private let f: (_UpdatedChildComponent, UIView, CGPoint, ComponentTransition) -> Void
public init(_ f: @escaping (_UpdatedChildComponent, UIView, CGPoint, Transition) -> Void) {
public init(_ f: @escaping (_UpdatedChildComponent, UIView, CGPoint, ComponentTransition) -> Void) {
self.f = f
}
public func callAsFunction(component: _UpdatedChildComponent, view: UIView, guide: CGPoint, transition: Transition) {
public func callAsFunction(component: _UpdatedChildComponent, view: UIView, guide: CGPoint, transition: ComponentTransition) {
self.f(component, view, guide, transition)
}
}
final class Disappear {
private let f: (UIView, Transition, @escaping () -> Void) -> Void
private let f: (UIView, ComponentTransition, @escaping () -> Void) -> Void
public init(_ f: @escaping (UIView, Transition, @escaping () -> Void) -> Void) {
public init(_ f: @escaping (UIView, ComponentTransition, @escaping () -> Void) -> Void) {
self.f = f
}
public func callAsFunction(view: UIView, transition: Transition, completion: @escaping () -> Void) {
public func callAsFunction(view: UIView, transition: ComponentTransition, completion: @escaping () -> Void) {
self.f(view, transition, completion)
}
}
@ -598,26 +598,26 @@ public extension Transition {
case update
}
private let f: (Stage, UIView, CGPoint, Transition, @escaping () -> Void) -> Void
private let f: (Stage, UIView, CGPoint, ComponentTransition, @escaping () -> Void) -> Void
public init(_ f: @escaping (Stage, UIView, CGPoint, Transition, @escaping () -> Void) -> Void
public init(_ f: @escaping (Stage, UIView, CGPoint, ComponentTransition, @escaping () -> Void) -> Void
) {
self.f = f
}
public func callAsFunction(stage: Stage, view: UIView, guide: CGPoint, transition: Transition, completion: @escaping () -> Void) {
public func callAsFunction(stage: Stage, view: UIView, guide: CGPoint, transition: ComponentTransition, completion: @escaping () -> Void) {
self.f(stage, view, guide, transition, completion)
}
}
final class Update {
private let f: (_UpdatedChildComponent, UIView, Transition) -> Void
private let f: (_UpdatedChildComponent, UIView, ComponentTransition) -> Void
public init(_ f: @escaping (_UpdatedChildComponent, UIView, Transition) -> Void) {
public init(_ f: @escaping (_UpdatedChildComponent, UIView, ComponentTransition) -> Void) {
self.f = f
}
public func callAsFunction(component: _UpdatedChildComponent, view: UIView, transition: Transition) {
public func callAsFunction(component: _UpdatedChildComponent, view: UIView, transition: ComponentTransition) {
self.f(component, view, transition)
}
}
@ -628,7 +628,7 @@ public extension CombinedComponent {
return UIView()
}
func update(view: View, availableSize: CGSize, state: State, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: State, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
let context = view.getCombinedComponentContext(Self.self)
let storedBody: Body
@ -683,7 +683,7 @@ public extension CombinedComponent {
previousView.transition = updatedChild.transitionDisappear
previousView.transitionWithGuide = updatedChild.transitionDisappearWithGuide
(updatedChild.transitionUpdate ?? Transition.Update.default)(component: updatedChild, view: updatedChild.view, transition: transition)
(updatedChild.transitionUpdate ?? ComponentTransition.Update.default)(component: updatedChild, view: updatedChild.view, transition: transition)
} else {
for i in index ..< context.childViewIndices.count {
if let moveView = context.childViews[context.childViewIndices[i]] {

View file

@ -89,13 +89,13 @@ extension UIView {
}
open class ComponentState {
open var _updated: ((Transition, Bool) -> Void)?
open var _updated: ((ComponentTransition, Bool) -> Void)?
var isUpdated: Bool = false
public init() {
}
public final func updated(transition: Transition = .immediate, isLocal: Bool = false) {
public final func updated(transition: ComponentTransition = .immediate, isLocal: Bool = false) {
self.isUpdated = true
self._updated?(transition, isLocal)
}
@ -107,7 +107,7 @@ public final class EmptyComponentState: ComponentState {
public protocol _TypeErasedComponent {
func _makeView() -> UIView
func _makeContext() -> _TypeErasedComponentContext
func _update(view: UIView, availableSize: CGSize, environment: Any, transition: Transition) -> CGSize
func _update(view: UIView, availableSize: CGSize, environment: Any, transition: ComponentTransition) -> CGSize
func _isEqual(to other: _TypeErasedComponent) -> Bool
}
@ -127,7 +127,7 @@ public protocol Component: _TypeErasedComponent, Equatable {
func makeView() -> View
func makeState() -> State
func update(view: View, availableSize: CGSize, state: State, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize
func update(view: View, availableSize: CGSize, state: State, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize
}
public extension Component {
@ -139,7 +139,7 @@ public extension Component {
return ComponentContext<Self>(component: self, environment: Environment<EnvironmentType>(), state: self.makeState())
}
func _update(view: UIView, availableSize: CGSize, environment: Any, transition: Transition) -> CGSize {
func _update(view: UIView, availableSize: CGSize, environment: Any, transition: ComponentTransition) -> CGSize {
let view = view as! Self.View
return self.update(view: view, availableSize: availableSize, state: view.context(component: self).state, environment: environment as! Environment<EnvironmentType>, transition: transition)
@ -191,7 +191,7 @@ public class AnyComponent<EnvironmentType>: _TypeErasedComponent, Equatable {
return self.wrapped._makeContext()
}
public func _update(view: UIView, availableSize: CGSize, environment: Any, transition: Transition) -> CGSize {
public func _update(view: UIView, availableSize: CGSize, environment: Any, transition: ComponentTransition) -> CGSize {
return self.wrapped._update(view: view, availableSize: availableSize, environment: environment as! Environment<EnvironmentType>, transition: transition)
}

View file

@ -17,7 +17,7 @@ public extension UIView {
}
private extension CALayer {
func animate(from: AnyObject, to: AnyObject, keyPath: String, duration: Double, delay: Double, curve: Transition.Animation.Curve, removeOnCompletion: Bool, additive: Bool, completion: ((Bool) -> Void)? = nil) {
func animate(from: AnyObject, to: AnyObject, keyPath: String, duration: Double, delay: Double, curve: ComponentTransition.Animation.Curve, removeOnCompletion: Bool, additive: Bool, completion: ((Bool) -> Void)? = nil) {
let timingFunction: String
let mediaTimingFunction: CAMediaTimingFunction?
switch curve {
@ -44,7 +44,7 @@ private extension CALayer {
}
}
private extension Transition.Animation.Curve {
private extension ComponentTransition.Animation.Curve {
func asTimingFunction() -> CAMediaTimingFunction {
switch self {
case .easeInOut:
@ -59,7 +59,7 @@ private extension Transition.Animation.Curve {
}
}
public extension Transition.Animation {
public extension ComponentTransition.Animation {
var isImmediate: Bool {
if case .none = self {
return true
@ -69,7 +69,7 @@ public extension Transition.Animation {
}
}
public struct Transition {
public struct ComponentTransition {
public enum Animation {
public enum Curve {
case easeInOut
@ -111,19 +111,19 @@ public struct Transition {
return nil
}
public func withUserData(_ userData: Any) -> Transition {
public func withUserData(_ userData: Any) -> ComponentTransition {
var result = self
result._userData.append(userData)
return result
}
public func withAnimation(_ animation: Animation) -> Transition {
public func withAnimation(_ animation: Animation) -> ComponentTransition {
var result = self
result.animation = animation
return result
}
public func withAnimationIfAnimated(_ animation: Animation) -> Transition {
public func withAnimationIfAnimated(_ animation: Animation) -> ComponentTransition {
switch self.animation {
case .none:
return self
@ -134,14 +134,14 @@ public struct Transition {
}
}
public static var immediate: Transition = Transition(animation: .none)
public static var immediate: ComponentTransition = ComponentTransition(animation: .none)
public static func easeInOut(duration: Double) -> Transition {
return Transition(animation: .curve(duration: duration, curve: .easeInOut))
public static func easeInOut(duration: Double) -> ComponentTransition {
return ComponentTransition(animation: .curve(duration: duration, curve: .easeInOut))
}
public static func spring(duration: Double) -> Transition {
return Transition(animation: .curve(duration: duration, curve: .spring))
public static func spring(duration: Double) -> ComponentTransition {
return ComponentTransition(animation: .curve(duration: duration, curve: .spring))
}
public init(animation: Animation) {
@ -1184,7 +1184,7 @@ public struct Transition {
}
}
public func animateContentsImage(layer: CALayer, from fromImage: CGImage, to toImage: CGImage, duration: Double, curve: Transition.Animation.Curve, completion: ((Bool) -> Void)? = nil) {
public func animateContentsImage(layer: CALayer, from fromImage: CGImage, to toImage: CGImage, duration: Double, curve: ComponentTransition.Animation.Curve, completion: ((Bool) -> Void)? = nil) {
layer.animate(
from: fromImage,
to: toImage,

View file

@ -154,7 +154,7 @@ public final class Button: Component {
}
}
private func updateAlpha(transition: Transition) {
private func updateAlpha(transition: ComponentTransition) {
guard let component = self.component else {
return
}
@ -271,7 +271,7 @@ public final class Button: Component {
super.cancelTracking(with: event)
}
func update(component: Button, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(component: Button, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
let contentSize = self.contentView.update(
transition: transition,
component: component.content,
@ -301,7 +301,7 @@ public final class Button: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -34,7 +34,7 @@ public final class Circle: Component {
var component: Circle?
var currentSize: CGSize?
func update(component: Circle, availableSize: CGSize, transition: Transition) -> CGSize {
func update(component: Circle, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
let size = CGSize(width: min(availableSize.width, component.size.width), height: min(availableSize.height, component.size.height))
if self.currentSize != size || self.component != component {
@ -63,7 +63,7 @@ public final class Circle: Component {
return View()
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -44,7 +44,7 @@ public final class Image: Component {
preconditionFailure()
}
func update(component: Image, availableSize: CGSize, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(component: Image, availableSize: CGSize, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.image = component.image
self.contentMode = component.contentMode
@ -63,7 +63,7 @@ public final class Image: Component {
return View()
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, environment: environment, transition: transition)
}
}

View file

@ -12,9 +12,9 @@ public final class List<ChildEnvironment: Equatable>: CombinedComponent {
private let items: [AnyComponentWithIdentity<ChildEnvironment>]
private let direction: Direction
private let centerAlignment: Bool
private let appear: Transition.Appear
private let appear: ComponentTransition.Appear
public init(_ items: [AnyComponentWithIdentity<ChildEnvironment>], direction: Direction = .vertical, centerAlignment: Bool = false, appear: Transition.Appear = .default()) {
public init(_ items: [AnyComponentWithIdentity<ChildEnvironment>], direction: Direction = .vertical, centerAlignment: Bool = false, appear: ComponentTransition.Appear = .default()) {
self.items = items
self.direction = direction
self.centerAlignment = centerAlignment

View file

@ -53,7 +53,7 @@ public final class Rectangle: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
var size = availableSize
if let width = self.width {
size.width = min(size.width, width)

View file

@ -47,7 +47,7 @@ public final class RoundedRectangle: Component {
public final class View: UIImageView {
var component: RoundedRectangle?
func update(component: RoundedRectangle, availableSize: CGSize, transition: Transition) -> CGSize {
func update(component: RoundedRectangle, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
if self.component != component {
let cornerRadius = component.cornerRadius ?? min(availableSize.width, availableSize.height) * 0.5
@ -113,7 +113,7 @@ public final class RoundedRectangle: Component {
return View()
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -95,7 +95,7 @@ public final class Text: Component {
return View()
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize)
}
}

View file

@ -37,13 +37,13 @@ public final class ComponentHostView<EnvironmentType>: UIView {
fatalError("init(coder:) has not been implemented")
}
public func update(transition: Transition, component: AnyComponent<EnvironmentType>, @EnvironmentBuilder environment: () -> Environment<EnvironmentType>, forceUpdate: Bool = false, containerSize: CGSize) -> CGSize {
public func update(transition: ComponentTransition, component: AnyComponent<EnvironmentType>, @EnvironmentBuilder environment: () -> Environment<EnvironmentType>, forceUpdate: Bool = false, containerSize: CGSize) -> CGSize {
let size = self._update(transition: transition, component: component, maybeEnvironment: environment, updateEnvironment: true, forceUpdate: forceUpdate, containerSize: containerSize)
self.currentSize = size
return size
}
private func _update(transition: Transition, component: AnyComponent<EnvironmentType>, maybeEnvironment: () -> Environment<EnvironmentType>, updateEnvironment: Bool, forceUpdate: Bool, containerSize: CGSize) -> CGSize {
private func _update(transition: ComponentTransition, component: AnyComponent<EnvironmentType>, maybeEnvironment: () -> Environment<EnvironmentType>, updateEnvironment: Bool, forceUpdate: Bool, containerSize: CGSize) -> CGSize {
precondition(!self.isUpdating)
self.isUpdating = true
@ -150,13 +150,13 @@ public final class ComponentView<EnvironmentType> {
fatalError("init(coder:) has not been implemented")
}
public func update(transition: Transition, component: AnyComponent<EnvironmentType>, @EnvironmentBuilder environment: () -> Environment<EnvironmentType>, forceUpdate: Bool = false, containerSize: CGSize) -> CGSize {
public func update(transition: ComponentTransition, component: AnyComponent<EnvironmentType>, @EnvironmentBuilder environment: () -> Environment<EnvironmentType>, forceUpdate: Bool = false, containerSize: CGSize) -> CGSize {
let size = self._update(transition: transition, component: component, maybeEnvironment: environment, updateEnvironment: true, forceUpdate: forceUpdate, containerSize: containerSize)
self.currentSize = size
return size
}
public func updateEnvironment(transition: Transition, @EnvironmentBuilder environment: () -> Environment<EnvironmentType>) -> CGSize? {
public func updateEnvironment(transition: ComponentTransition, @EnvironmentBuilder environment: () -> Environment<EnvironmentType>) -> CGSize? {
guard let currentComponent = self.currentComponent, let currentContainerSize = self.currentContainerSize else {
return nil
}
@ -165,7 +165,7 @@ public final class ComponentView<EnvironmentType> {
return size
}
private func _update(transition: Transition, component: AnyComponent<EnvironmentType>, maybeEnvironment: () -> Environment<EnvironmentType>, updateEnvironment: Bool, forceUpdate: Bool, containerSize: CGSize) -> CGSize {
private func _update(transition: ComponentTransition, component: AnyComponent<EnvironmentType>, maybeEnvironment: () -> Environment<EnvironmentType>, updateEnvironment: Bool, forceUpdate: Bool, containerSize: CGSize) -> CGSize {
precondition(!self.isUpdating)
self.isUpdating = true

View file

@ -27,7 +27,7 @@ public final class ActivityIndicatorComponent: Component {
fatalError("init(coder:) has not been implemented")
}
func update(component: ActivityIndicatorComponent, availableSize: CGSize, transition: Transition) -> CGSize {
func update(component: ActivityIndicatorComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
if component.color != self.color {
self.color = component.color
}
@ -44,7 +44,7 @@ public final class ActivityIndicatorComponent: Component {
return View()
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -91,7 +91,7 @@ public final class AnimatedStickerComponent: Component {
fatalError("init(coder:) has not been implemented")
}
func update(component: AnimatedStickerComponent, availableSize: CGSize, transition: Transition) -> CGSize {
func update(component: AnimatedStickerComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
if self.component?.animation != component.animation {
self.animationNode?.view.removeFromSuperview()
@ -145,7 +145,7 @@ public final class AnimatedStickerComponent: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -144,7 +144,7 @@ public final class BalancedTextComponent: Component {
return self.textView.attributeSubstring(name: name, index: index)
}
public func update(component: BalancedTextComponent, availableSize: CGSize, transition: Transition) -> CGSize {
public func update(component: BalancedTextComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
let attributedString: NSAttributedString
switch component.text {
case let .plain(string):
@ -203,7 +203,7 @@ public final class BalancedTextComponent: Component {
return View()
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -36,7 +36,7 @@ public final class BlurredBackgroundComponent: Component {
private var tintContainerView: UIView?
private var vibrancyEffectView: UIVisualEffectView?
public func update(component: BlurredBackgroundComponent, availableSize: CGSize, transition: Transition) -> CGSize {
public func update(component: BlurredBackgroundComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
self.updateColor(color: component.color, transition: transition.containedViewLayoutTransition)
self.update(size: availableSize, cornerRadius: component.cornerRadius, transition: transition.containedViewLayoutTransition)
@ -56,7 +56,7 @@ public final class BlurredBackgroundComponent: Component {
return View(color: nil, enableBlur: true)
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -39,7 +39,7 @@ public final class BundleIconComponent: Component {
fatalError("init(coder:) has not been implemented")
}
func update(component: BundleIconComponent, availableSize: CGSize, transition: Transition) -> CGSize {
func update(component: BundleIconComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
if self.component?.name != component.name || self.component?.tintColor != component.tintColor {
if let tintColor = component.tintColor {
self.image = generateTintedImage(image: UIImage(bundleImageName: component.name), color: tintColor, backgroundColor: nil)
@ -62,7 +62,7 @@ public final class BundleIconComponent: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -3,7 +3,7 @@ import UIKit
import ComponentFlow
import Display
public extension Transition.Animation.Curve {
public extension ComponentTransition.Animation.Curve {
init(_ curve: ContainedViewLayoutTransitionCurve) {
switch curve {
case .linear:
@ -33,13 +33,13 @@ public extension Transition.Animation.Curve {
}
}
public extension Transition {
public extension ComponentTransition {
init(_ transition: ContainedViewLayoutTransition) {
switch transition {
case .immediate:
self.init(animation: .none)
case let .animated(duration, curve):
self.init(animation: .curve(duration: duration, curve: Transition.Animation.Curve(curve)))
self.init(animation: .curve(duration: duration, curve: ComponentTransition.Animation.Curve(curve)))
}
}

View file

@ -133,7 +133,7 @@ public final class CreditCardInputComponent: Component {
}
}
func update(component: CreditCardInputComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(component: CreditCardInputComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
switch component.dataType {
case .cardNumber:
self.textField.autoFormattingBehavior = .cardNumbers
@ -166,7 +166,7 @@ public final class CreditCardInputComponent: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -71,7 +71,7 @@ public final class PrefixSectionGroupComponent: Component {
fatalError("init(coder:) has not been implemented")
}
func update(component: PrefixSectionGroupComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(component: PrefixSectionGroupComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
let spacing: CGFloat = 16.0
let sideInset: CGFloat = 16.0
@ -188,7 +188,7 @@ public final class PrefixSectionGroupComponent: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -58,7 +58,7 @@ public final class TextInputComponent: Component {
self.component?.updated(self.text ?? "")
}
func update(component: TextInputComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(component: TextInputComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.font = UIFont.systemFont(ofSize: 17.0)
self.textColor = component.textColor
@ -80,7 +80,7 @@ public final class TextInputComponent: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -146,7 +146,7 @@ public final class LottieAnimationComponent: Component {
}
}
func update(component: LottieAnimationComponent, availableSize: CGSize, transition: Transition) -> CGSize {
func update(component: LottieAnimationComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
var updatePlayback = false
var updateColors = false
@ -319,7 +319,7 @@ public final class LottieAnimationComponent: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -120,7 +120,7 @@ public final class MultilineTextComponent: Component {
}
public final class View: ImmediateTextView {
public func update(component: MultilineTextComponent, availableSize: CGSize, transition: Transition) -> CGSize {
public func update(component: MultilineTextComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
let attributedString: NSAttributedString
switch component.text {
case let .plain(string):
@ -169,7 +169,7 @@ public final class MultilineTextComponent: Component {
return View()
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -145,7 +145,7 @@ public final class MultilineTextWithEntitiesComponent: Component {
fatalError("init(coder:) has not been implemented")
}
public func update(component: MultilineTextWithEntitiesComponent, availableSize: CGSize, transition: Transition) -> CGSize {
public func update(component: MultilineTextWithEntitiesComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
let attributedString: NSAttributedString
switch component.text {
case let .plain(string):
@ -205,7 +205,7 @@ public final class MultilineTextWithEntitiesComponent: Component {
return View()
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -14,7 +14,7 @@ open class PagerExternalTopPanelContainer: SparseContainerView {
}
public protocol PagerContentViewWithBackground: UIView {
func pagerUpdateBackground(backgroundFrame: CGRect, topPanelHeight: CGFloat, transition: Transition)
func pagerUpdateBackground(backgroundFrame: CGRect, topPanelHeight: CGFloat, transition: ComponentTransition)
}
public final class PagerComponentChildEnvironment: Equatable {
@ -24,7 +24,7 @@ public final class PagerComponentChildEnvironment: Equatable {
public var absoluteOffsetToBottomEdge: CGFloat?
public var isReset: Bool
public var isInteracting: Bool
public var transition: Transition
public var transition: ComponentTransition
public init(
relativeOffset: CGFloat,
@ -32,7 +32,7 @@ public final class PagerComponentChildEnvironment: Equatable {
absoluteOffsetToBottomEdge: CGFloat?,
isReset: Bool,
isInteracting: Bool,
transition: Transition
transition: ComponentTransition
) {
self.relativeOffset = relativeOffset
self.absoluteOffsetToTopEdge = absoluteOffsetToTopEdge
@ -78,8 +78,8 @@ public final class PagerComponentPanelEnvironment<TopPanelEnvironment>: Equatabl
public let contentAccessoryRightButtons: [AnyComponentWithIdentity<Empty>]
public let activeContentId: AnyHashable?
public let navigateToContentId: (AnyHashable) -> Void
public let visibilityFractionUpdated: ActionSlot<(CGFloat, Transition)>
public let isExpandedUpdated: (Bool, Transition) -> Void
public let visibilityFractionUpdated: ActionSlot<(CGFloat, ComponentTransition)>
public let isExpandedUpdated: (Bool, ComponentTransition) -> Void
init(
isContentInFocus: Bool,
@ -90,8 +90,8 @@ public final class PagerComponentPanelEnvironment<TopPanelEnvironment>: Equatabl
contentAccessoryRightButtons: [AnyComponentWithIdentity<Empty>],
activeContentId: AnyHashable?,
navigateToContentId: @escaping (AnyHashable) -> Void,
visibilityFractionUpdated: ActionSlot<(CGFloat, Transition)>,
isExpandedUpdated: @escaping (Bool, Transition) -> Void
visibilityFractionUpdated: ActionSlot<(CGFloat, ComponentTransition)>,
isExpandedUpdated: @escaping (Bool, ComponentTransition) -> Void
) {
self.isContentInFocus = isContentInFocus
self.contentOffset = contentOffset
@ -206,9 +206,9 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
public let externalTopPanelContainer: PagerExternalTopPanelContainer?
public let bottomPanel: AnyComponent<PagerComponentPanelEnvironment<TopPanelEnvironment>>?
public let externalBottomPanelContainer: PagerExternalTopPanelContainer?
public let panelStateUpdated: ((PagerComponentPanelState, Transition) -> Void)?
public let isTopPanelExpandedUpdated: (Bool, Transition) -> Void
public let isTopPanelHiddenUpdated: (Bool, Transition) -> Void
public let panelStateUpdated: ((PagerComponentPanelState, ComponentTransition) -> Void)?
public let isTopPanelExpandedUpdated: (Bool, ComponentTransition) -> Void
public let isTopPanelHiddenUpdated: (Bool, ComponentTransition) -> Void
public let contentIdUpdated: (AnyHashable) -> Void
public let panelHideBehavior: PagerComponentPanelHideBehavior
public let clipContentToTopPanel: Bool
@ -228,9 +228,9 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
externalTopPanelContainer: PagerExternalTopPanelContainer?,
bottomPanel: AnyComponent<PagerComponentPanelEnvironment<TopPanelEnvironment>>?,
externalBottomPanelContainer: PagerExternalTopPanelContainer?,
panelStateUpdated: ((PagerComponentPanelState, Transition) -> Void)?,
isTopPanelExpandedUpdated: @escaping (Bool, Transition) -> Void,
isTopPanelHiddenUpdated: @escaping (Bool, Transition) -> Void,
panelStateUpdated: ((PagerComponentPanelState, ComponentTransition) -> Void)?,
isTopPanelExpandedUpdated: @escaping (Bool, ComponentTransition) -> Void,
isTopPanelHiddenUpdated: @escaping (Bool, ComponentTransition) -> Void,
contentIdUpdated: @escaping (AnyHashable) -> Void,
panelHideBehavior: PagerComponentPanelHideBehavior,
clipContentToTopPanel: Bool,
@ -329,9 +329,9 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
private var contentClippingView: UIView
private var contentViews: [AnyHashable: ContentView] = [:]
private var contentBackgroundView: ComponentHostView<Empty>?
private let topPanelVisibilityFractionUpdated = ActionSlot<(CGFloat, Transition)>()
private let topPanelVisibilityFractionUpdated = ActionSlot<(CGFloat, ComponentTransition)>()
private var topPanelView: ComponentHostView<PagerComponentPanelEnvironment<TopPanelEnvironment>>?
private let bottomPanelVisibilityFractionUpdated = ActionSlot<(CGFloat, Transition)>()
private let bottomPanelVisibilityFractionUpdated = ActionSlot<(CGFloat, ComponentTransition)>()
private var bottomPanelView: ComponentHostView<PagerComponentPanelEnvironment<TopPanelEnvironment>>?
private var topPanelHeight: CGFloat?
@ -440,9 +440,9 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
}
if updateTopPanelExpanded {
self.isTopPanelExpandedUpdated(isExpanded: false, transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
self.isTopPanelExpandedUpdated(isExpanded: false, transition: ComponentTransition(animation: .curve(duration: 0.4, curve: .spring)))
} else {
self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
self.state?.updated(transition: ComponentTransition(animation: .curve(duration: 0.4, curve: .spring)))
}
if let centralId = self.centralId {
self.component?.contentIdUpdated(centralId)
@ -472,7 +472,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
/*paneTransitionGestureState.fraction = 1.0
self.paneTransitionGestureState = paneTransitionGestureState
self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))*/
self.state?.updated(transition: ComponentTransition(animation: .curve(duration: 0.4, curve: .spring)))*/
self.centralId = id
@ -484,19 +484,19 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
}
if updateTopPanelExpanded {
self.isTopPanelExpandedUpdated(isExpanded: false, transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
self.isTopPanelExpandedUpdated(isExpanded: false, transition: ComponentTransition(animation: .curve(duration: 0.4, curve: .spring)))
} else {
self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
self.state?.updated(transition: ComponentTransition(animation: .curve(duration: 0.4, curve: .spring)))
}
self.component?.contentIdUpdated(id)
}
func update(component: PagerComponent<ChildEnvironmentType, TopPanelEnvironment>, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
func update(component: PagerComponent<ChildEnvironmentType, TopPanelEnvironment>, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
let previousPanelHideBehavior = self.component?.panelHideBehavior
var panelStateTransition = transition
if let previousPanelHideBehavior = previousPanelHideBehavior, previousPanelHideBehavior != component.panelHideBehavior, panelStateTransition.animation.isImmediate {
panelStateTransition = Transition(animation: .curve(duration: 0.3, curve: .spring))
panelStateTransition = ComponentTransition(animation: .curve(duration: 0.3, curve: .spring))
}
self.component = component
@ -1005,7 +1005,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
if self.isTopPanelExpanded {
self.isTopPanelExpanded = false
self.component?.isTopPanelExpandedUpdated(self.isTopPanelExpanded, Transition(animation: .curve(duration: 0.25, curve: .easeInOut)))
self.component?.isTopPanelExpandedUpdated(self.isTopPanelExpanded, ComponentTransition(animation: .curve(duration: 0.25, curve: .easeInOut)))
}
}
}
@ -1017,12 +1017,12 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
if contentView.wantsExclusiveMode != wantsExclusiveMode {
contentView.wantsExclusiveMode = wantsExclusiveMode
//self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
self.component?.isTopPanelHiddenUpdated(wantsExclusiveMode, Transition(animation: .curve(duration: 0.4, curve: .spring)))
//self.state?.updated(transition: ComponentTransition(animation: .curve(duration: 0.4, curve: .spring)))
self.component?.isTopPanelHiddenUpdated(wantsExclusiveMode, ComponentTransition(animation: .curve(duration: 0.4, curve: .spring)))
}
}
private func isTopPanelExpandedUpdated(isExpanded: Bool, transition: Transition) {
private func isTopPanelExpandedUpdated(isExpanded: Bool, transition: ComponentTransition) {
if self.isTopPanelExpanded == isExpanded {
return
}
@ -1036,7 +1036,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
return
}
self.isTopPanelExpandedUpdated(isExpanded: false, transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
self.isTopPanelExpandedUpdated(isExpanded: false, transition: ComponentTransition(animation: .curve(duration: 0.4, curve: .spring)))
}
}
@ -1044,7 +1044,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -67,7 +67,7 @@ public final class ProgressIndicatorComponent: Component {
return CAShapeLayer.self
}
func update(component: ProgressIndicatorComponent, availableSize: CGSize, transition: Transition) -> CGSize {
func update(component: ProgressIndicatorComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
let lineWidth: CGFloat = 1.33
let size = CGSize(width: component.diameter, height: component.diameter)
@ -107,7 +107,7 @@ public final class ProgressIndicatorComponent: Component {
return View()
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -302,7 +302,7 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
private var currentHasInputHeight = false
private var currentAvailableSize: CGSize?
func update(component: SheetComponent<ChildEnvironmentType>, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
func update(component: SheetComponent<ChildEnvironmentType>, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
let previousHasInputHeight = self.currentHasInputHeight
let sheetEnvironment = environment[SheetComponentEnvironment.self].value
component.animateOut.connect { [weak self] completion in
@ -424,7 +424,7 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -122,7 +122,7 @@ public final class SolidRoundedButtonComponent: Component {
private var currentIsLoading = false
public func update(component: SolidRoundedButtonComponent, availableSize: CGSize, transition: Transition) -> CGSize {
public func update(component: SolidRoundedButtonComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
if self.button == nil {
let button = SolidRoundedButtonView(
title: component.title,
@ -182,7 +182,7 @@ public final class SolidRoundedButtonComponent: Component {
return View()
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -48,7 +48,7 @@ public final class UndoPanelComponent: Component {
fatalError("init(coder:) has not been implemented")
}
public func update(component: UndoPanelComponent, availableSize: CGSize, transition: Transition) -> CGSize {
public func update(component: UndoPanelComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
self.effect = UIBlurEffect(style: .dark)
self.layer.cornerRadius = 10.0
@ -61,7 +61,7 @@ public final class UndoPanelComponent: Component {
return View()
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -22,14 +22,14 @@ public final class UndoPanelContainerComponent: Component {
private var nextPanel: UndoPanelComponent?
public func update(component: UndoPanelContainerComponent, availableSize: CGSize, state: EmptyComponentState, transition: Transition) -> CGSize {
public func update(component: UndoPanelContainerComponent, availableSize: CGSize, state: EmptyComponentState, transition: ComponentTransition) -> CGSize {
component.push.connect { [weak self, weak state] panel in
guard let strongSelf = self, let state = state else {
return
}
strongSelf.nextPanel = panel
state.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))
state.updated(transition: ComponentTransition(animation: .curve(duration: 0.4, curve: .spring)))
}
var animateTopPanelIn = false
@ -77,7 +77,7 @@ public final class UndoPanelContainerComponent: Component {
return View()
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, transition: transition)
}
}

View file

@ -166,7 +166,7 @@ open class ViewControllerComponentContainer: ViewController {
self.view.addSubview(self.hostView)
}
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: Transition) {
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ComponentTransition) {
self.currentLayout = (layout, navigationHeight)
let environment = ViewControllerComponentContainer.Environment(
@ -206,10 +206,10 @@ open class ViewControllerComponentContainer: ViewController {
guard let currentLayout = self.currentLayout else {
return
}
self.containerLayoutUpdated(layout: currentLayout.layout, navigationHeight: currentLayout.navigationHeight, transition: animated ? Transition(animation: .none).withUserData(isVisible ? AnimateInTransition() : AnimateOutTransition()) : .immediate)
self.containerLayoutUpdated(layout: currentLayout.layout, navigationHeight: currentLayout.navigationHeight, transition: animated ? ComponentTransition(animation: .none).withUserData(isVisible ? AnimateInTransition() : AnimateOutTransition()) : .immediate)
}
func updateComponent(component: AnyComponent<ViewControllerComponentContainer.Environment>, transition: Transition) {
func updateComponent(component: AnyComponent<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) {
self.component = component
guard let currentLayout = self.currentLayout else {
@ -369,10 +369,10 @@ open class ViewControllerComponentContainer: ViewController {
let navigationHeight = self.navigationLayout(layout: layout).navigationFrame.maxY
self.validLayout = layout
self.node.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: Transition(transition))
self.node.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: ComponentTransition(transition))
}
public func updateComponent(component: AnyComponent<ViewControllerComponentContainer.Environment>, transition: Transition) {
public func updateComponent(component: AnyComponent<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) {
self.node.updateComponent(component: component, transition: transition)
}
}

View file

@ -266,7 +266,7 @@ final class ComposePollScreenComponent: Component {
}
}
private func updateScrolling(transition: Transition) {
private func updateScrolling(transition: ComponentTransition) {
let navigationAlphaDistance: CGFloat = 16.0
let navigationAlpha: CGFloat = max(0.0, min(1.0, self.scrollView.contentOffset.y / navigationAlphaDistance))
if let controller = self.environment?.controller(), let navigationBar = controller.navigationBar {
@ -297,7 +297,7 @@ final class ComposePollScreenComponent: Component {
effectiveInputHeight: CGFloat,
metrics: LayoutMetrics,
deviceMetrics: DeviceMetrics,
transition: Transition
transition: ComponentTransition
) -> CGFloat {
let bottomInset: CGFloat = bottomInset + 8.0
let bottomContainerInset: CGFloat = 0.0
@ -377,8 +377,8 @@ final class ComposePollScreenComponent: Component {
if needsInputActivation {
let inputNodeFrame = inputNodeFrame.offsetBy(dx: 0.0, dy: inputNodeHeight)
Transition.immediate.setFrame(layer: inputMediaNode.layer, frame: inputNodeFrame)
Transition.immediate.setFrame(layer: self.inputMediaNodeBackground, frame: inputNodeBackgroundFrame)
ComponentTransition.immediate.setFrame(layer: inputMediaNode.layer, frame: inputNodeFrame)
ComponentTransition.immediate.setFrame(layer: self.inputMediaNodeBackground, frame: inputNodeBackgroundFrame)
}
if animateIn {
@ -472,7 +472,7 @@ final class ComposePollScreenComponent: Component {
return textInputStates
}
func update(component: ComposePollScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
func update(component: ComposePollScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
self.isUpdating = true
defer {
self.isUpdating = false
@ -622,7 +622,7 @@ final class ComposePollScreenComponent: Component {
return
}
if !self.isUpdating {
self.state?.updated(transition: Transition(transition))
self.state?.updated(transition: ComponentTransition(transition))
}
}
)
@ -1458,7 +1458,7 @@ final class ComposePollScreenComponent: Component {
return View()
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -173,12 +173,12 @@ public final class ListComposePollOptionComponent: Component {
self.layer.removeAnimation(forKey: "transform.scale")
if animateScale {
let transition = Transition(animation: .curve(duration: 0.2, curve: .easeInOut))
let transition = ComponentTransition(animation: .curve(duration: 0.2, curve: .easeInOut))
transition.setScale(layer: self.layer, scale: topScale)
}
} else {
if animateScale {
let transition = Transition(animation: .none)
let transition = ComponentTransition(animation: .none)
transition.setScale(layer: self.layer, scale: 1.0)
self.layer.animateScale(from: topScale, to: maxScale, duration: 0.13, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false, completion: { [weak self] _ in
@ -202,7 +202,7 @@ public final class ListComposePollOptionComponent: Component {
self.action?()
}
func update(size: CGSize, theme: PresentationTheme, isSelected: Bool, transition: Transition) {
func update(size: CGSize, theme: PresentationTheme, isSelected: Bool, transition: ComponentTransition) {
let checkLayer: CheckLayer
if let current = self.checkLayer {
checkLayer = current
@ -291,7 +291,7 @@ public final class ListComposePollOptionComponent: Component {
}
}
func update(component: ListComposePollOptionComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(component: ListComposePollOptionComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.isUpdating = true
defer {
self.isUpdating = false
@ -455,12 +455,12 @@ public final class ListComposePollOptionComponent: Component {
)
let modeSelectorFrame = CGRect(origin: CGPoint(x: size.width - 4.0 - modeSelectorSize.width, y: floor((size.height - modeSelectorSize.height) * 0.5)), size: modeSelectorSize)
if let modeSelectorView = modeSelector.view as? PlainButtonComponent.View {
let alphaTransition: Transition = .easeInOut(duration: 0.2)
let alphaTransition: ComponentTransition = .easeInOut(duration: 0.2)
if modeSelectorView.superview == nil {
self.addSubview(modeSelectorView)
Transition.immediate.setAlpha(view: modeSelectorView, alpha: 0.0)
Transition.immediate.setScale(view: modeSelectorView, scale: 0.001)
ComponentTransition.immediate.setAlpha(view: modeSelectorView, alpha: 0.0)
ComponentTransition.immediate.setScale(view: modeSelectorView, scale: 0.001)
}
if playAnimation, let animationView = modeSelectorView.contentView as? LottieComponent.View {
@ -481,7 +481,7 @@ public final class ListComposePollOptionComponent: Component {
self.modeSelector = nil
if let modeSelectorView = modeSelector.view {
if !transition.animation.isImmediate {
let alphaTransition: Transition = .easeInOut(duration: 0.2)
let alphaTransition: ComponentTransition = .easeInOut(duration: 0.2)
alphaTransition.setAlpha(view: modeSelectorView, alpha: 0.0, completion: { [weak modeSelectorView] _ in
modeSelectorView?.removeFromSuperview()
})
@ -497,7 +497,7 @@ public final class ListComposePollOptionComponent: Component {
return size
}
public func updateCustomPlaceholder(value: String, size: CGSize, transition: Transition) {
public func updateCustomPlaceholder(value: String, size: CGSize, transition: ComponentTransition) {
guard let component = self.component else {
return
}
@ -554,7 +554,7 @@ public final class ListComposePollOptionComponent: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -354,7 +354,7 @@ final class ContactsControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
)
let navigationBarSize = self.navigationBarView.update(
transition: Transition(transition),
transition: ComponentTransition(transition),
component: AnyComponent(ChatListNavigationBar(
context: self.context,
theme: self.presentationData.theme,
@ -420,7 +420,7 @@ final class ContactsControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
}
if let navigationBarComponentView = self.navigationBarView.view as? ChatListNavigationBar.View {
navigationBarComponentView.applyScroll(offset: offset, allowAvatarsExpansion: false, transition: Transition(transition))
navigationBarComponentView.applyScroll(offset: offset, allowAvatarsExpansion: false, transition: ComponentTransition(transition))
}
}
@ -450,7 +450,7 @@ final class ContactsControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
if let navigationBarComponentView = self.navigationBarView.view as? ChatListNavigationBar.View {
navigationBarComponentView.deferScrollApplication = false
navigationBarComponentView.applyCurrentScroll(transition: Transition(transition))
navigationBarComponentView.applyCurrentScroll(transition: ComponentTransition(transition))
}
}

View file

@ -1131,7 +1131,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
lineWidth: 1.33,
inactiveLineWidth: 1.33
),
transition: animated ? Transition(animation: .curve(duration: 0.25, curve: .easeInOut)) : .immediate
transition: animated ? ComponentTransition(animation: .curve(duration: 0.25, curve: .easeInOut)) : .immediate
)
if strongSelf.avatarTapRecognizer == nil {

View file

@ -635,7 +635,7 @@ final class ContextSourceContainer: ASDisplayNode {
return TabSelectorComponent.Item(id: source.id, title: source.title)
}
let tabSelectorSize = tabSelector.update(
transition: Transition(transition),
transition: ComponentTransition(transition),
component: AnyComponent(TabSelectorComponent(
colors: TabSelectorComponent.Colors(
foreground: presentationData.theme.contextMenu.primaryColor.withMultipliedAlpha(0.8),
@ -678,7 +678,7 @@ final class ContextSourceContainer: ASDisplayNode {
}
let closeButtonSize = closeButton.update(
transition: Transition(transition),
transition: ComponentTransition(transition),
component: AnyComponent(PlainButtonComponent(
content: AnyComponent(
CloseButtonComponent(

View file

@ -1990,12 +1990,6 @@ extension CGRect: AnyValueProviding {
}
}
extension CATransform3D: Equatable {
public static func ==(lhs: CATransform3D, rhs: CATransform3D) -> Bool {
return CATransform3DEqualToTransform(lhs, rhs)
}
}
extension CATransform3D: AnyValueProviding {
func interpolate(with other: CATransform3D, fraction: CGFloat) -> CATransform3D {
return CATransform3D(
@ -2025,7 +2019,7 @@ extension CATransform3D: AnyValueProviding {
stringValue: { "\(self)" },
isEqual: { other in
if let otherValue = other.value as? CATransform3D {
return self == otherValue
return CATransform3DEqualToTransform(self, otherValue)
} else {
return false
}
@ -2112,7 +2106,7 @@ final class ControlledTransitionProperty {
return "MyCustomAnimation_\(Unmanaged.passUnretained(self).toOpaque())"
}()
init<T: Equatable>(layer: CALayer, path: String, fromValue: T, toValue: T, completion: ((Bool) -> Void)?) where T: AnyValueProviding {
init<T>(layer: CALayer, path: String, fromValue: T, toValue: T, completion: ((Bool) -> Void)?) where T: AnyValueProviding {
self.layer = layer
self.path = path
self.fromValue = fromValue.anyValue
@ -2333,7 +2327,7 @@ public final class ControlledTransition {
}
public func updateTransform(layer: CALayer, transform: CATransform3D, completion: ((Bool) -> Void)?) {
if layer.transform == transform {
if CATransform3DEqualToTransform(layer.transform, transform) {
return
}
let fromValue: CATransform3D

View file

@ -15,7 +15,7 @@ public struct KeyShortcut: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(self.input)
hasher.combine(self.modifiers)
hasher.combine(self.modifiers.rawValue)
}
public static func ==(lhs: KeyShortcut, rhs: KeyShortcut) -> Bool {
@ -23,12 +23,6 @@ public struct KeyShortcut: Hashable {
}
}
extension UIKeyModifierFlags: Hashable {
public var hashValue: Int {
return self.rawValue
}
}
extension KeyShortcut {
var uiKeyCommand: UIKeyCommand {
let command = UIKeyCommand(input: self.input, modifierFlags: self.modifiers, action: #selector(KeyShortcutsController.handleKeyCommand(_:)), discoverabilityTitle: self.title)

View file

@ -306,7 +306,7 @@ private class ColorSliderComponent: Component {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
view.updated = self.updated
return view.updateLayout(size: availableSize, leftColor: self.leftColor, rightColor: self.rightColor, currentColor: self.currentColor, value: self.value)
}
@ -456,7 +456,7 @@ private class ColorFieldComponent: Component {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
view.updated = self.updated
return view.updateLayout(size: availableSize, component: self)
}
@ -548,7 +548,7 @@ private class ColorPreviewComponent: Component {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.updateLayout(size: availableSize, color: self.color)
}
}
@ -724,7 +724,7 @@ final class ColorGridComponent: Component {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
view.selected = self.selected
return view.updateLayout(size: availableSize, selectedColor: self.color)
}
@ -935,7 +935,7 @@ final class ColorSpectrumComponent: Component {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
view.selected = self.selected
return view.updateLayout(size: availableSize, selectedColor: self.color)
}
@ -1533,7 +1533,7 @@ private class SegmentedControlComponent: Component {
preconditionFailure()
}
func update(component: SegmentedControlComponent, availableSize: CGSize, transition: Transition) -> CGSize {
func update(component: SegmentedControlComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
self.node.items = component.values.map { SegmentedControlItem(title: $0) }
self.node.selectedIndex = component.selectedIndex
let selectionChanged = component.selectionChanged
@ -1556,7 +1556,7 @@ private class SegmentedControlComponent: Component {
return View()
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}
@ -1748,7 +1748,7 @@ final class ColorSwatchComponent: Component {
self.contentView.layer.animateScale(from: 1.0, to: 0.01, duration: 0.3)
}
func update(component: ColorSwatchComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(component: ColorSwatchComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.component = component
let contentSize: CGSize
if case .pallete = component.type {
@ -1850,7 +1850,7 @@ final class ColorSwatchComponent: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -824,7 +824,7 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
break
}
let transition = Transition.easeInOut(duration: 0.2)
let transition = ComponentTransition.easeInOut(duration: 0.2)
if isTrappedInBin, let binView = self.bin.view {
if !selectedEntityView.isTrappedInBin {
let refs = [
@ -921,7 +921,7 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
self.bringSubviewToFront(binView)
}
binView.frame = binFrame
Transition.easeInOut(duration: 0.2).setAlpha(view: binView, alpha: location != nil ? 1.0 : 0.0, delay: location == nil && wasOpened ? 0.4 : 0.0)
ComponentTransition.easeInOut(duration: 0.2).setAlpha(view: binView, alpha: location != nil ? 1.0 : 0.0, delay: location == nil && wasOpened ? 0.4 : 0.0)
}
return isOpened
}
@ -1189,7 +1189,7 @@ private final class EntityBinComponent: Component {
}
private var wasOpened = false
func update(component: EntityBinComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(component: EntityBinComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.component = component
self.state = state
@ -1234,7 +1234,7 @@ private final class EntityBinComponent: Component {
return View()
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -127,7 +127,7 @@ public class DrawingReactionEntityView: DrawingStickerEntityView {
reactionContextNode.updateLayout(size: availableSize, insets: insets, anchorRect: anchorRect, centerAligned: true, isCoveredByInput: false, isAnimatingOut: false, transition: transition)
}
let reactionContextNodeTransition: Transition = .immediate
let reactionContextNodeTransition: ComponentTransition = .immediate
let reactionContextNode: ReactionContextNode
reactionContextNode = ReactionContextNode(
context: self.context,

View file

@ -416,7 +416,7 @@ private final class BlurredGradientComponent: Component {
private var gradientMask = UIImageView()
private var gradientForeground = SimpleGradientLayer()
public func update(component: BlurredGradientComponent, availableSize: CGSize, transition: Transition) -> CGSize {
public func update(component: BlurredGradientComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
self.component = component
self.isUserInteractionEnabled = false
@ -452,7 +452,7 @@ private final class BlurredGradientComponent: Component {
return View(color: nil, enableBlur: true)
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}
@ -1303,12 +1303,12 @@ private final class DrawingScreenComponent: CombinedComponent {
)
context.add(textSettings
.position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height - environment.safeInsets.bottom - textSettings.size.height / 2.0 - 89.0 - additionalBottomInset))
.appear(Transition.Appear({ _, view, transition in
.appear(ComponentTransition.Appear({ _, view, transition in
if let view = view as? TextSettingsComponent.View, !transition.animation.isImmediate {
view.animateIn()
}
}))
.disappear(Transition.Disappear({ view, transition, completion in
.disappear(ComponentTransition.Disappear({ view, transition, completion in
if let view = view as? TextSettingsComponent.View, !transition.animation.isImmediate {
view.animateOut(completion: completion)
} else {
@ -1353,11 +1353,11 @@ private final class DrawingScreenComponent: CombinedComponent {
)
context.add(swatch1Button
.position(CGPoint(x: offsetX, y: context.availableSize.height - environment.safeInsets.bottom - swatch1Button.size.height / 2.0 - 57.0 - additionalBottomInset))
.appear(Transition.Appear { _, view, transition in
.appear(ComponentTransition.Appear { _, view, transition in
transition.animateScale(view: view, from: 0.1, to: 1.0)
transition.animateAlpha(view: view, from: 0.0, to: 1.0)
})
.disappear(Transition.Disappear { view, transition, completion in
.disappear(ComponentTransition.Disappear { view, transition, completion in
transition.setScale(view: view, scale: 0.1)
transition.setAlpha(view: view, alpha: 0.0, completion: { _ in
completion()
@ -1381,11 +1381,11 @@ private final class DrawingScreenComponent: CombinedComponent {
)
context.add(swatch2Button
.position(CGPoint(x: offsetX, y: context.availableSize.height - environment.safeInsets.bottom - swatch2Button.size.height / 2.0 - 57.0 - additionalBottomInset))
.appear(Transition.Appear { _, view, transition in
.appear(ComponentTransition.Appear { _, view, transition in
transition.animateScale(view: view, from: 0.1, to: 1.0, delay: 0.025)
transition.animateAlpha(view: view, from: 0.0, to: 1.0, delay: 0.025)
})
.disappear(Transition.Disappear { view, transition, completion in
.disappear(ComponentTransition.Disappear { view, transition, completion in
transition.setScale(view: view, scale: 0.1)
transition.setAlpha(view: view, alpha: 0.0, completion: { _ in
completion()
@ -1409,11 +1409,11 @@ private final class DrawingScreenComponent: CombinedComponent {
)
context.add(swatch3Button
.position(CGPoint(x: offsetX, y: context.availableSize.height - environment.safeInsets.bottom - swatch3Button.size.height / 2.0 - 57.0 - additionalBottomInset))
.appear(Transition.Appear { _, view, transition in
.appear(ComponentTransition.Appear { _, view, transition in
transition.animateScale(view: view, from: 0.1, to: 1.0, delay: 0.05)
transition.animateAlpha(view: view, from: 0.0, to: 1.0, delay: 0.05)
})
.disappear(Transition.Disappear { view, transition, completion in
.disappear(ComponentTransition.Disappear { view, transition, completion in
transition.setScale(view: view, scale: 0.1)
transition.setAlpha(view: view, alpha: 0.0, completion: { _ in
completion()
@ -1437,11 +1437,11 @@ private final class DrawingScreenComponent: CombinedComponent {
)
context.add(swatch4Button
.position(CGPoint(x: offsetX, y: context.availableSize.height - environment.safeInsets.bottom - swatch4Button.size.height / 2.0 - 57.0 - additionalBottomInset))
.appear(Transition.Appear { _, view, transition in
.appear(ComponentTransition.Appear { _, view, transition in
transition.animateScale(view: view, from: 0.1, to: 1.0, delay: 0.075)
transition.animateAlpha(view: view, from: 0.0, to: 1.0, delay: 0.075)
})
.disappear(Transition.Disappear { view, transition, completion in
.disappear(ComponentTransition.Disappear { view, transition, completion in
transition.setScale(view: view, scale: 0.1)
transition.setAlpha(view: view, alpha: 0.0, completion: { _ in
completion()
@ -1465,11 +1465,11 @@ private final class DrawingScreenComponent: CombinedComponent {
)
context.add(swatch5Button
.position(CGPoint(x: offsetX, y: context.availableSize.height - environment.safeInsets.bottom - swatch5Button.size.height / 2.0 - 57.0 - additionalBottomInset))
.appear(Transition.Appear { _, view, transition in
.appear(ComponentTransition.Appear { _, view, transition in
transition.animateScale(view: view, from: 0.1, to: 1.0, delay: 0.1)
transition.animateAlpha(view: view, from: 0.0, to: 1.0, delay: 0.1)
})
.disappear(Transition.Disappear { view, transition, completion in
.disappear(ComponentTransition.Disappear { view, transition, completion in
transition.setScale(view: view, scale: 0.1)
transition.setAlpha(view: view, alpha: 0.0, completion: { _ in
completion()
@ -1494,11 +1494,11 @@ private final class DrawingScreenComponent: CombinedComponent {
)
context.add(swatch6Button
.position(CGPoint(x: offsetX, y: context.availableSize.height - environment.safeInsets.bottom - swatch6Button.size.height / 2.0 - 57.0 - additionalBottomInset))
.appear(Transition.Appear { _, view, transition in
.appear(ComponentTransition.Appear { _, view, transition in
transition.animateScale(view: view, from: 0.1, to: 1.0, delay: 0.125)
transition.animateAlpha(view: view, from: 0.0, to: 1.0, delay: 0.125)
})
.disappear(Transition.Disappear { view, transition, completion in
.disappear(ComponentTransition.Disappear { view, transition, completion in
transition.setScale(view: view, scale: 0.1)
transition.setAlpha(view: view, alpha: 0.0, completion: { _ in
completion()
@ -1522,11 +1522,11 @@ private final class DrawingScreenComponent: CombinedComponent {
)
context.add(swatch7Button
.position(CGPoint(x: offsetX, y: context.availableSize.height - environment.safeInsets.bottom - swatch7Button.size.height / 2.0 - 57.0 - additionalBottomInset))
.appear(Transition.Appear { _, view, transition in
.appear(ComponentTransition.Appear { _, view, transition in
transition.animateScale(view: view, from: 0.1, to: 1.0, delay: 0.15)
transition.animateAlpha(view: view, from: 0.0, to: 1.0, delay: 0.15)
})
.disappear(Transition.Disappear { view, transition, completion in
.disappear(ComponentTransition.Disappear { view, transition, completion in
transition.setScale(view: view, scale: 0.1)
transition.setAlpha(view: view, alpha: 0.0, completion: { _ in
completion()
@ -1550,11 +1550,11 @@ private final class DrawingScreenComponent: CombinedComponent {
)
context.add(swatch8Button
.position(CGPoint(x: offsetX, y: context.availableSize.height - environment.safeInsets.bottom - swatch7Button.size.height / 2.0 - 57.0 - additionalBottomInset))
.appear(Transition.Appear { _, view, transition in
.appear(ComponentTransition.Appear { _, view, transition in
transition.animateScale(view: view, from: 0.1, to: 1.0, delay: 0.175)
transition.animateAlpha(view: view, from: 0.0, to: 1.0, delay: 0.175)
})
.disappear(Transition.Disappear { view, transition, completion in
.disappear(ComponentTransition.Disappear { view, transition, completion in
transition.setScale(view: view, scale: 0.1)
transition.setAlpha(view: view, alpha: 0.0, completion: { _ in
completion()
@ -1592,12 +1592,12 @@ private final class DrawingScreenComponent: CombinedComponent {
)
context.add(tools
.position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height - environment.safeInsets.bottom - tools.size.height / 2.0 - 78.0 - additionalBottomInset))
.appear(Transition.Appear({ _, view, transition in
.appear(ComponentTransition.Appear({ _, view, transition in
if let view = view as? ToolsComponent.View, !transition.animation.isImmediate {
view.animateIn(completion: {})
}
}))
.disappear(Transition.Disappear({ view, transition, completion in
.disappear(ComponentTransition.Disappear({ view, transition, completion in
if let view = view as? ToolsComponent.View, !transition.animation.isImmediate {
view.animateOut(completion: completion)
} else {
@ -2012,13 +2012,13 @@ private final class DrawingScreenComponent: CombinedComponent {
}
context.add(doneButton
.position(doneButtonPosition)
.appear(Transition.Appear { _, view, transition in
.appear(ComponentTransition.Appear { _, view, transition in
transition.animateScale(view: view, from: 0.1, to: 1.0)
transition.animateAlpha(view: view, from: 0.0, to: 1.0)
transition.animatePosition(view: view, from: CGPoint(x: 12.0, y: 0.0), to: CGPoint(), additive: true)
})
.disappear(Transition.Disappear { view, transition, completion in
.disappear(ComponentTransition.Disappear { view, transition, completion in
transition.setScale(view: view, scale: 0.1)
transition.setAlpha(view: view, alpha: 0.0, completion: { _ in
completion()
@ -2614,13 +2614,13 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController, U
return result
}
func requestUpdate(transition: Transition = .immediate) {
func requestUpdate(transition: ComponentTransition = .immediate) {
if let (layout, orientation) = self.validLayout {
self.containerLayoutUpdated(layout: layout, orientation: orientation, transition: transition)
}
}
func containerLayoutUpdated(layout: ContainerViewLayout, orientation: UIInterfaceOrientation?, forceUpdate: Bool = false, animateOut: Bool = false, transition: Transition) {
func containerLayoutUpdated(layout: ContainerViewLayout, orientation: UIInterfaceOrientation?, forceUpdate: Bool = false, animateOut: Bool = false, transition: ComponentTransition) {
guard let controller = self.controller else {
return
}
@ -2922,7 +2922,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController, U
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)
(self.displayNode as! Node).containerLayoutUpdated(layout: layout, orientation: self.orientation, transition: Transition(transition))
(self.displayNode as! Node).containerLayoutUpdated(layout: layout, orientation: self.orientation, transition: ComponentTransition(transition))
}
public func adapterContainerLayoutUpdatedSize(_ size: CGSize, intrinsicInsets: UIEdgeInsets, safeInsets: UIEdgeInsets, statusBarHeight: CGFloat, inputHeight: CGFloat, orientation: UIInterfaceOrientation, isRegular: Bool, animated: Bool) {
@ -3531,7 +3531,7 @@ public final class DrawingToolsInteraction {
}
}
public func containerLayoutUpdated(layout: ContainerViewLayout, transition: Transition) {
public func containerLayoutUpdated(layout: ContainerViewLayout, transition: ComponentTransition) {
self.validLayout = layout
guard self.isActive else {

View file

@ -1045,7 +1045,7 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, UIPencilInt
}
func setBrushSizePreview(_ size: CGFloat?) {
let transition = Transition(animation: .curve(duration: 0.2, curve: .easeInOut))
let transition = ComponentTransition(animation: .curve(duration: 0.2, curve: .easeInOut))
if let size = size {
let minLineWidth = max(1.0, max(self.frame.width, self.frame.height) * 0.002)
let maxLineWidth = max(10.0, max(self.frame.width, self.frame.height) * 0.07)

View file

@ -181,7 +181,7 @@ final class ModeAndSizeComponent: Component {
self.backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
}
func update(component: ModeAndSizeComponent, availableSize: CGSize, transition: Transition) -> CGSize {
func update(component: ModeAndSizeComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
self.component = component
self.updated = component.sizeUpdated
@ -259,7 +259,7 @@ final class ModeAndSizeComponent: Component {
return View()
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View file

@ -141,7 +141,7 @@ final class TextAlignmentComponent: Component {
fatalError("init(coder:) has not been implemented")
}
func update(component: TextAlignmentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(component: TextAlignmentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
let height = 2.0 - UIScreenPixel
let spacing: CGFloat = 3.0 + UIScreenPixel
let long = 21.0
@ -175,7 +175,7 @@ final class TextAlignmentComponent: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
@ -228,7 +228,7 @@ final class TextFontComponent: Component {
}
}
func update(component: TextFontComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(component: TextFontComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.component = component
if self.icon.contents == nil {
@ -281,7 +281,7 @@ final class TextFontComponent: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
@ -530,7 +530,7 @@ final class TextSettingsComponent: CombinedComponent {
)
context.add(styleButton
.position(CGPoint(x: offset + styleButton.size.width / 2.0, y: context.availableSize.height / 2.0))
.update(Transition.Update { _, view, transition in
.update(ComponentTransition.Update { _, view, transition in
if let snapshot = view.snapshotView(afterScreenUpdates: false) {
transition.setAlpha(view: snapshot, alpha: 0.0, completion: { [weak snapshot] _ in
snapshot?.removeFromSuperview()
@ -749,7 +749,7 @@ public final class TextSizeSliderComponent: Component {
return true
}
func updateLayout(size: CGSize, component: TextSizeSliderComponent, transition: Transition) -> CGSize {
func updateLayout(size: CGSize, component: TextSizeSliderComponent, transition: ComponentTransition) -> CGSize {
self.component = component
let previousSize = self.validSize
@ -797,7 +797,7 @@ public final class TextSizeSliderComponent: Component {
return View()
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
view.updated = self.updated
view.released = self.released
return view.updateLayout(size: availableSize, component: self, transition: transition)

View file

@ -295,7 +295,7 @@ final class ToolsComponent: Component {
}
func animateOut(completion: @escaping () -> Void) {
let transition = Transition(animation: .curve(duration: 0.2, curve: .easeInOut))
let transition = ComponentTransition(animation: .curve(duration: 0.2, curve: .easeInOut))
var delay = 0.0
for i in 0 ..< self.toolViews.count {
let view = self.toolViews[i]
@ -306,7 +306,7 @@ final class ToolsComponent: Component {
}
}
func update(component: ToolsComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(component: ToolsComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.component = component
if self.toolViews.isEmpty {
@ -467,7 +467,7 @@ final class ToolsComponent: Component {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -72,6 +72,18 @@ enum BaseConstants {
return numberFormatter
}()
static let starNumberFormatter: NumberFormatter = {
let numberFormatter = NumberFormatter()
numberFormatter.allowsFloats = true
numberFormatter.numberStyle = .decimal
numberFormatter.usesGroupingSeparator = true
numberFormatter.groupingSeparator = " "
numberFormatter.minimumIntegerDigits = 1
numberFormatter.minimumFractionDigits = 0
numberFormatter.maximumFractionDigits = 2
return numberFormatter
}()
static let detailsNumberFormatter: NumberFormatter = {
let detailsNumberFormatter = NumberFormatter()
detailsNumberFormatter.allowsFloats = false

View file

@ -33,7 +33,7 @@ public class GeneralLinesChartController: BaseLinesChartController {
private var prevoiusHorizontalStrideInterval: Int = 1
private (set) var chartLines: [LinesChartRenderer.LineData] = []
private(set) var chartLines: [LinesChartRenderer.LineData] = []
override public init(chartsCollection: ChartsCollection) {
self.initialChartCollection = chartsCollection

View file

@ -25,7 +25,7 @@ class BarsComponentController: GeneralChartComponentController {
let previewBarsChartRenderer: BarChartRenderer
private(set) var barsWidth: CGFloat = 1
private (set) var chartBars: BarChartRenderer.BarsData = .blank
private(set) var chartBars: BarChartRenderer.BarsData = .blank
private var step: Bool

View file

@ -13,7 +13,23 @@ import Cocoa
import UIKit
#endif
public enum GraphCurrency : String {
case xtr = "XTR"
case ton = "TON"
var formatter: NumberFormatter {
switch self {
case .xtr:
return BaseConstants.starNumberFormatter
case .ton:
return BaseConstants.tonNumberFormatter
}
}
}
public class StackedBarsChartController: BaseChartController {
let barsController: BarsComponentController
let zoomedBarsController: BarsComponentController
@ -23,12 +39,12 @@ public class StackedBarsChartController: BaseChartController {
}
}
public init(chartsCollection: ChartsCollection, isCrypto: Bool = false, rate: Double = 1.0) {
public init(chartsCollection: ChartsCollection, currency: GraphCurrency? = nil, drawCurrency:((CGContext, UIColor, CGPoint)->Void)? = nil, rate: Double = 1.0) {
let horizontalScalesRenderer = HorizontalScalesRenderer()
let verticalScalesRenderer = VerticalScalesRenderer()
var secondaryScalesRenderer: VerticalScalesRenderer?
if isCrypto {
verticalScalesRenderer.isCrypto = true
if let _ = currency {
verticalScalesRenderer.drawCurrency = drawCurrency
secondaryScalesRenderer = VerticalScalesRenderer()
secondaryScalesRenderer?.isRightAligned = true
}
@ -38,10 +54,10 @@ public class StackedBarsChartController: BaseChartController {
verticalScalesRenderer: verticalScalesRenderer,
secondaryScalesRenderer: secondaryScalesRenderer,
previewBarsChartRenderer: BarChartRenderer())
if isCrypto {
if let currency {
barsController.conversionRate = rate
barsController.verticalLimitsNumberFormatter = BaseConstants.tonNumberFormatter
barsController.detailsNumberFormatter = BaseConstants.tonNumberFormatter
barsController.verticalLimitsNumberFormatter = currency.formatter
barsController.detailsNumberFormatter = currency.formatter
}
zoomedBarsController = BarsComponentController(isZoomed: true,
mainBarsRenderer: BarChartRenderer(),

View file

@ -9,7 +9,7 @@
import Foundation
#if os(macOS)
import Cocoa
typealias UIColor = NSColor
public typealias UIColor = NSColor
#else
import UIKit
#endif
@ -26,7 +26,7 @@ class VerticalScalesRenderer: BaseChartRenderer {
var axisXWidth: CGFloat = GView.oneDevicePixel
var isRightAligned: Bool = false
var isCrypto: Bool = false
var drawCurrency:((CGContext, UIColor, CGPoint)->Void)?
var horizontalLinesColor: GColor = .black {
didSet {
@ -122,45 +122,6 @@ class VerticalScalesRenderer: BaseChartRenderer {
context.strokeLineSegments(between: lineSegments)
}
func drawTonSymbol(context: CGContext, color: UIColor, at point: CGPoint) {
let width: CGFloat = 8.0
let height: CGFloat = 7.5
let cornerRadius: CGFloat = 0.5
let topPoint = CGPoint(x: point.x + width / 2, y: point.y)
let bottomPoint = CGPoint(x: point.x + width / 2, y: point.y + height)
let leftTopPoint = CGPoint(x: point.x, y: point.y)
let rightTopPoint = CGPoint(x: point.x + width, y: point.y)
context.saveGState()
context.beginPath()
context.move(to: CGPoint(x: leftTopPoint.x + cornerRadius, y: leftTopPoint.y))
context.addArc(tangent1End: leftTopPoint, tangent2End: bottomPoint, radius: cornerRadius)
context.addLine(to: CGPoint(x: bottomPoint.x, y: bottomPoint.y - cornerRadius + GView.oneDevicePixel))
context.move(to: CGPoint(x: rightTopPoint.x - cornerRadius, y: rightTopPoint.y))
context.addArc(tangent1End: rightTopPoint, tangent2End: bottomPoint, radius: cornerRadius)
context.addLine(to: CGPoint(x: bottomPoint.x, y: bottomPoint.y - cornerRadius + GView.oneDevicePixel))
context.move(to: CGPoint(x: leftTopPoint.x + cornerRadius, y: leftTopPoint.y))
context.addLine(to: CGPoint(x: rightTopPoint.x - cornerRadius, y: rightTopPoint.y))
context.move(to: topPoint)
context.addLine(to: CGPoint(x: bottomPoint.x, y: bottomPoint.y - 1.0))
context.setLineWidth(1.0)
context.setLineCap(.round)
context.setFillColor(UIColor.clear.cgColor)
context.setStrokeColor(color.withAlphaComponent(1.0).cgColor)
context.setAlpha(color.alphaValue)
context.strokePath()
context.restoreGState()
}
func drawVerticalLabels(_ labels: [LinesChartLabel], attributes: [NSAttributedString.Key: Any]) {
if isRightAligned {
for label in labels {
@ -176,9 +137,9 @@ class VerticalScalesRenderer: BaseChartRenderer {
let textNode = LabelNode.layoutText(attributedString, bounds.size)
var xOffset = 0.0
if self.isCrypto {
if let drawCurrency {
xOffset += 11.0
drawTonSymbol(context: context, color: attributes[.foregroundColor] as? UIColor ?? .black, at: CGPoint(x: chartFrame.minX, y: y + 4.0))
drawCurrency(context, attributes[.foregroundColor] as? UIColor ?? .black, CGPoint(x: chartFrame.minX, y: y + 4.0))
}
textNode.1.draw(CGRect(origin: CGPoint(x: chartFrame.minX + xOffset, y: y), size: textNode.0.size), in: context, backingScaleFactor: deviceScale)

View file

@ -16,7 +16,7 @@ import UIKit
private let milionsScale = "M"
private let thousandsScale = "K"
class ScalesNumberFormatter: NumberFormatter {
class ScalesNumberFormatter: NumberFormatter, @unchecked Sendable {
override func string(from number: NSNumber) -> String? {
let value = number.doubleValue
let pow = log10(value)
@ -36,7 +36,7 @@ class ScalesNumberFormatter: NumberFormatter {
}
}
class TonNumberFormatter: NumberFormatter {
class TonNumberFormatter: NumberFormatter, @unchecked Sendable {
override func string(from number: NSNumber) -> String? {
var balanceText = "\(number.intValue)"
let decimalSeparator = self.decimalSeparator ?? "."
@ -60,3 +60,5 @@ class TonNumberFormatter: NumberFormatter {
return balanceText
}
}

View file

@ -21,7 +21,7 @@ func makeCIColor(color: GColor) -> CIColor {
#endif
}
extension GColor {
public extension GColor {
var redValue: CGFloat{ return makeCIColor(color: self).red }
var greenValue: CGFloat{ return makeCIColor(color: self).green }
var blueValue: CGFloat{ return makeCIColor(color: self).blue }

View file

@ -20,6 +20,6 @@ public typealias GView = UIView
#endif
extension GView {
public extension GView {
static let oneDevicePixel: CGFloat = (1.0 / max(2, min(1, deviceScale)))
}

View file

@ -87,7 +87,7 @@ public func createChartController(_ data: String, type: ChartType, rate: Double
controller = StackedBarsChartController(chartsCollection: collection)
controller.isZoomable = false
case .currency:
controller = StackedBarsChartController(chartsCollection: collection, isCrypto: true, rate: rate)
controller = StackedBarsChartController(chartsCollection: collection, currency: .ton, rate: rate)
controller.isZoomable = false
case .step:
controller = StepBarsChartController(chartsCollection: collection)

View file

@ -94,7 +94,7 @@ class ChartVisibilityView: UIView {
}
}
private (set) var selectedItems: [Bool] = []
private(set) var selectedItems: [Bool] = []
var isExpanded: Bool = true {
didSet {
invalidateIntrinsicContentSize()

View file

@ -457,7 +457,7 @@ final class HashtagSearchControllerNode: ASDisplayNode, ASGestureRecognizerDeleg
var topInset: CGFloat = insets.top - 89.0
if let state = self.globalStorySearchState {
let componentView: ComponentView<Empty>
var panelTransition = Transition(transition)
var panelTransition = ComponentTransition(transition)
if let current = self.globalStorySearchComponentView {
componentView = current
} else {

View file

@ -143,7 +143,7 @@ final class HashtagSearchNavigationContentNode: NavigationBarContentNode {
items.append(TabSelectorComponent.Item(id: AnyHashable(2), title: self.strings.HashtagSearch_PublicPosts))
let tabSelectorSize = self.tabSelector.update(
transition: Transition(transition),
transition: ComponentTransition(transition),
component: AnyComponent(TabSelectorComponent(
colors: TabSelectorComponent.Colors(
foreground: self.theme.list.itemSecondaryTextColor,

View file

@ -212,7 +212,7 @@ final class InstantPageDetailsArrowNode : ASDisplayNode {
self.setNeedsDisplay()
}
}
private (set) var open: Bool
private(set) var open: Bool
private var progress: CGFloat = 0.0
private var targetProgress: CGFloat?

View file

@ -57,7 +57,7 @@ public final class ItemListControllerSegmentedTitleView: UIView {
self.update(transition: .immediate)
}
private func update(transition: Transition) {
private func update(transition: ComponentTransition) {
guard let size = self.validLayout else {
return
}

View file

@ -78,7 +78,7 @@ final class ItemListControllerTabsContentNode: NavigationBarContentNode {
}
let tabSelectorSize = self.tabSelector.update(
transition: Transition(transition),
transition: ComponentTransition(transition),
component: AnyComponent(TabSelectorComponent(
colors: TabSelectorComponent.Colors(
foreground: self.theme.list.itemSecondaryTextColor,

View file

@ -297,7 +297,7 @@ final class JoinLinkPreviewPeerContentNode: ASDisplayNode, ShareContentContainer
let animationRenderer = self.context.animationRenderer
let avatarIcon: ComponentView<Empty>
var avatarIconTransition = Transition(transition)
var avatarIconTransition = ComponentTransition(transition)
if let current = self.avatarIcon {
avatarIcon = current
} else {

Some files were not shown because too many files have changed in this diff Show more