mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
d050cf8ce9
400 changed files with 2718 additions and 2409 deletions
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ¢er, 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> ¤tLayer();
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ¢er, 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];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ¢er, 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() {
|
||||
|
|
|
|||
|
|
@ -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 ¢er, 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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ¢er, 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() {
|
||||
|
|
|
|||
|
|
@ -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 ¢er, 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;
|
||||
|
|
|
|||
|
|
@ -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)"))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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"],
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)))
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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]] {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ class ChartVisibilityView: UIView {
|
|||
}
|
||||
}
|
||||
|
||||
private (set) var selectedItems: [Bool] = []
|
||||
private(set) var selectedItems: [Bool] = []
|
||||
var isExpanded: Bool = true {
|
||||
didSet {
|
||||
invalidateIntrinsicContentSize()
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue