mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 14:20:20 +00:00
Implement horizontal and vertical alignments for stack layout
This commit is contained in:
@@ -67,3 +67,27 @@ typedef NS_ENUM(NSUInteger, ASStackLayoutAlignSelf) {
|
|||||||
/** Expand to fill cross axis */
|
/** Expand to fill cross axis */
|
||||||
ASStackLayoutAlignSelfStretch,
|
ASStackLayoutAlignSelfStretch,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Orientation of children along horizontal axis */
|
||||||
|
typedef NS_ENUM(NSUInteger, ASHorizontalAlignment) {
|
||||||
|
/** No alignment specified. Default value */
|
||||||
|
ASHorizontalAlignmentNone,
|
||||||
|
/** Left aligned */
|
||||||
|
ASAlignmentLeft,
|
||||||
|
/** Center aligned */
|
||||||
|
ASAlignmentMiddle,
|
||||||
|
/** Right aligned */
|
||||||
|
ASAlignmentRight,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Orientation of children along vertical axis */
|
||||||
|
typedef NS_ENUM(NSUInteger, ASVerticalAlignment) {
|
||||||
|
/** No alignment specified. Default value */
|
||||||
|
ASVerticalAlignmentNone,
|
||||||
|
/** Top aligned */
|
||||||
|
ASAlignmentTop,
|
||||||
|
/** Center aligned */
|
||||||
|
ASAlignmentCenter,
|
||||||
|
/** Bottom aligned */
|
||||||
|
ASAlignmentBottom,
|
||||||
|
};
|
||||||
|
|||||||
@@ -35,10 +35,25 @@
|
|||||||
*/
|
*/
|
||||||
@interface ASStackLayoutSpec : ASLayoutSpec
|
@interface ASStackLayoutSpec : ASLayoutSpec
|
||||||
|
|
||||||
/** Specifies the direction children are stacked in. */
|
/**
|
||||||
|
Specifies the direction children are stacked in. If horizontalAlignment and verticalAlignment were set,
|
||||||
|
they will be resolved again, causing justifyContent and alignItems to be updated accordingly
|
||||||
|
*/
|
||||||
@property (nonatomic, assign) ASStackLayoutDirection direction;
|
@property (nonatomic, assign) ASStackLayoutDirection direction;
|
||||||
/** The amount of space between each child. */
|
/** The amount of space between each child. */
|
||||||
@property (nonatomic, assign) CGFloat spacing;
|
@property (nonatomic, assign) CGFloat spacing;
|
||||||
|
/**
|
||||||
|
Specifies how children are aligned horizontally. Depends on the stack direction, setting the alignment causes either
|
||||||
|
justifyContent or alignItems to be updated. The alignment will remain valid after future direction changes.
|
||||||
|
Thus, it is preferred to those properties
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) ASHorizontalAlignment horizontalAlignment;
|
||||||
|
/**
|
||||||
|
Specifies how children are aligned vertically. Depends on the stack direction, setting the alignment causes either
|
||||||
|
justifyContent or alignItems to be updated. The alignment will remain valid after future direction changes.
|
||||||
|
Thus, it is preferred to those properties
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) ASVerticalAlignment verticalAlignment;
|
||||||
/** The amount of space between each child. */
|
/** The amount of space between each child. */
|
||||||
@property (nonatomic, assign) ASStackLayoutJustifyContent justifyContent;
|
@property (nonatomic, assign) ASStackLayoutJustifyContent justifyContent;
|
||||||
/** Orientation of children along cross axis */
|
/** Orientation of children along cross axis */
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
@implementation ASStackLayoutSpec
|
@implementation ASStackLayoutSpec
|
||||||
{
|
{
|
||||||
ASDN::RecursiveMutex _propertyLock;
|
ASDN::RecursiveMutex _propertyLock;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
@@ -58,8 +58,10 @@
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
_direction = direction;
|
_direction = direction;
|
||||||
_alignItems = alignItems;
|
|
||||||
_spacing = spacing;
|
_spacing = spacing;
|
||||||
|
_horizontalAlignment = ASHorizontalAlignmentNone;
|
||||||
|
_verticalAlignment = ASVerticalAlignmentNone;
|
||||||
|
_alignItems = alignItems;
|
||||||
_justifyContent = justifyContent;
|
_justifyContent = justifyContent;
|
||||||
|
|
||||||
[self setChildren:children];
|
[self setChildren:children];
|
||||||
@@ -69,18 +71,44 @@
|
|||||||
- (void)setDirection:(ASStackLayoutDirection)direction
|
- (void)setDirection:(ASStackLayoutDirection)direction
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");
|
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");
|
||||||
_direction = direction;
|
if (_direction != direction) {
|
||||||
|
_direction = direction;
|
||||||
|
[self resolveHorizontalAlignment];
|
||||||
|
[self resolveVerticalAlignment];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setHorizontalAlignment:(ASHorizontalAlignment)horizontalAlignment
|
||||||
|
{
|
||||||
|
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");
|
||||||
|
if (_horizontalAlignment != horizontalAlignment) {
|
||||||
|
_horizontalAlignment = horizontalAlignment;
|
||||||
|
[self resolveHorizontalAlignment];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setVerticalAlignment:(ASVerticalAlignment)verticalAlignment
|
||||||
|
{
|
||||||
|
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");
|
||||||
|
if (_verticalAlignment != verticalAlignment) {
|
||||||
|
_verticalAlignment = verticalAlignment;
|
||||||
|
[self resolveVerticalAlignment];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setAlignItems:(ASStackLayoutAlignItems)alignItems
|
- (void)setAlignItems:(ASStackLayoutAlignItems)alignItems
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");
|
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");
|
||||||
|
ASDisplayNodeAssert(_horizontalAlignment == ASHorizontalAlignmentNone, @"Cannot set this property directly because horizontalAlignment is being used");
|
||||||
|
ASDisplayNodeAssert(_verticalAlignment == ASVerticalAlignmentNone, @"Cannot set this property directly because verticalAlignment is being used");
|
||||||
_alignItems = alignItems;
|
_alignItems = alignItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setJustifyContent:(ASStackLayoutJustifyContent)justifyContent
|
- (void)setJustifyContent:(ASStackLayoutJustifyContent)justifyContent
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");
|
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");
|
||||||
|
ASDisplayNodeAssert(_horizontalAlignment == ASHorizontalAlignmentNone, @"Cannot set this property directly because horizontalAlignment is being used");
|
||||||
|
ASDisplayNodeAssert(_verticalAlignment == ASVerticalAlignmentNone, @"Cannot set this property directly because verticalAlignment is being used");
|
||||||
_justifyContent = justifyContent;
|
_justifyContent = justifyContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,6 +177,24 @@
|
|||||||
sublayouts:sublayouts];
|
sublayouts:sublayouts];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)resolveHorizontalAlignment
|
||||||
|
{
|
||||||
|
if (_direction == ASStackLayoutDirectionHorizontal) {
|
||||||
|
_justifyContent = justifyContent(_horizontalAlignment, _justifyContent);
|
||||||
|
} else {
|
||||||
|
_alignItems = alignment(_horizontalAlignment, _alignItems);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resolveVerticalAlignment
|
||||||
|
{
|
||||||
|
if (_direction == ASStackLayoutDirectionHorizontal) {
|
||||||
|
_alignItems = alignment(_verticalAlignment, _alignItems);
|
||||||
|
} else {
|
||||||
|
_justifyContent = justifyContent(_verticalAlignment, _justifyContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ASStackLayoutSpec (Debugging)
|
@implementation ASStackLayoutSpec (Debugging)
|
||||||
|
|||||||
@@ -68,3 +68,63 @@ inline ASStackLayoutAlignItems alignment(ASStackLayoutAlignSelf childAlignment,
|
|||||||
return stackAlignment;
|
return stackAlignment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline ASStackLayoutAlignItems alignment(ASHorizontalAlignment alignment, ASStackLayoutAlignItems defaultAlignment)
|
||||||
|
{
|
||||||
|
switch (alignment) {
|
||||||
|
case ASAlignmentLeft:
|
||||||
|
return ASStackLayoutAlignItemsStart;
|
||||||
|
case ASAlignmentMiddle:
|
||||||
|
return ASStackLayoutAlignItemsCenter;
|
||||||
|
case ASAlignmentRight:
|
||||||
|
return ASStackLayoutAlignItemsEnd;
|
||||||
|
case ASHorizontalAlignmentNone:
|
||||||
|
default:
|
||||||
|
return defaultAlignment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ASStackLayoutAlignItems alignment(ASVerticalAlignment alignment, ASStackLayoutAlignItems defaultAlignment)
|
||||||
|
{
|
||||||
|
switch (alignment) {
|
||||||
|
case ASAlignmentTop:
|
||||||
|
return ASStackLayoutAlignItemsStart;
|
||||||
|
case ASAlignmentCenter:
|
||||||
|
return ASStackLayoutAlignItemsCenter;
|
||||||
|
case ASAlignmentBottom:
|
||||||
|
return ASStackLayoutAlignItemsEnd;
|
||||||
|
case ASVerticalAlignmentNone:
|
||||||
|
default:
|
||||||
|
return defaultAlignment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ASStackLayoutJustifyContent justifyContent(ASHorizontalAlignment alignment, ASStackLayoutJustifyContent defaultJustifyContent)
|
||||||
|
{
|
||||||
|
switch (alignment) {
|
||||||
|
case ASAlignmentLeft:
|
||||||
|
return ASStackLayoutJustifyContentStart;
|
||||||
|
case ASAlignmentMiddle:
|
||||||
|
return ASStackLayoutJustifyContentCenter;
|
||||||
|
case ASAlignmentRight:
|
||||||
|
return ASStackLayoutJustifyContentEnd;
|
||||||
|
case ASHorizontalAlignmentNone:
|
||||||
|
default:
|
||||||
|
return defaultJustifyContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ASStackLayoutJustifyContent justifyContent(ASVerticalAlignment alignment, ASStackLayoutJustifyContent defaultJustifyContent)
|
||||||
|
{
|
||||||
|
switch (alignment) {
|
||||||
|
case ASAlignmentTop:
|
||||||
|
return ASStackLayoutJustifyContentStart;
|
||||||
|
case ASAlignmentCenter:
|
||||||
|
return ASStackLayoutJustifyContentCenter;
|
||||||
|
case ASAlignmentBottom:
|
||||||
|
return ASStackLayoutJustifyContentEnd;
|
||||||
|
case ASVerticalAlignmentNone:
|
||||||
|
default:
|
||||||
|
return defaultJustifyContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
self.recordMode = NO;
|
self.recordMode = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Utility methods
|
||||||
|
|
||||||
static NSArray *defaultSubnodes()
|
static NSArray *defaultSubnodes()
|
||||||
{
|
{
|
||||||
return defaultSubnodesWithSameSize(CGSizeZero, NO);
|
return defaultSubnodesWithSameSize(CGSizeZero, NO);
|
||||||
@@ -63,6 +65,24 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
|
|||||||
[self testStackLayoutSpecWithStyle:style sizeRange:sizeRange subnodes:subnodes identifier:identifier];
|
[self testStackLayoutSpecWithStyle:style sizeRange:sizeRange subnodes:subnodes identifier:identifier];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)testStackLayoutSpecWithDirection:(ASStackLayoutDirection)direction
|
||||||
|
itemsHorizontalAlignment:(ASHorizontalAlignment)horizontalAlignment
|
||||||
|
itemsVerticalAlignment:(ASVerticalAlignment)verticalAlignment
|
||||||
|
identifier:(NSString *)identifier
|
||||||
|
{
|
||||||
|
NSArray *subnodes = defaultSubnodesWithSameSize({50, 50}, NO);
|
||||||
|
|
||||||
|
ASStackLayoutSpec *stackLayoutSpec = [[ASStackLayoutSpec alloc] init];
|
||||||
|
stackLayoutSpec.direction = direction;
|
||||||
|
stackLayoutSpec.children = subnodes;
|
||||||
|
[stackLayoutSpec setHorizontalAlignment:horizontalAlignment];
|
||||||
|
[stackLayoutSpec setVerticalAlignment:verticalAlignment];
|
||||||
|
|
||||||
|
CGSize exactSize = CGSizeMake(200, 200);
|
||||||
|
static ASSizeRange kSize = ASSizeRangeMake(exactSize, exactSize);
|
||||||
|
[self testStackLayoutSpec:stackLayoutSpec sizeRange:kSize subnodes:subnodes identifier:identifier];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)testStackLayoutSpecWithStyle:(ASStackLayoutSpecStyle)style
|
- (void)testStackLayoutSpecWithStyle:(ASStackLayoutSpecStyle)style
|
||||||
sizeRange:(ASSizeRange)sizeRange
|
sizeRange:(ASSizeRange)sizeRange
|
||||||
subnodes:(NSArray *)subnodes
|
subnodes:(NSArray *)subnodes
|
||||||
@@ -76,13 +96,23 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
|
|||||||
sizeRange:(ASSizeRange)sizeRange
|
sizeRange:(ASSizeRange)sizeRange
|
||||||
subnodes:(NSArray *)subnodes
|
subnodes:(NSArray *)subnodes
|
||||||
identifier:(NSString *)identifier
|
identifier:(NSString *)identifier
|
||||||
|
{
|
||||||
|
ASStackLayoutSpec *stackLayoutSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:style.direction
|
||||||
|
spacing:style.spacing
|
||||||
|
justifyContent:style.justifyContent
|
||||||
|
alignItems:style.alignItems
|
||||||
|
children:children];
|
||||||
|
[self testStackLayoutSpec:stackLayoutSpec sizeRange:sizeRange subnodes:subnodes identifier:identifier];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testStackLayoutSpec:(ASStackLayoutSpec *)stackLayoutSpec
|
||||||
|
sizeRange:(ASSizeRange)sizeRange
|
||||||
|
subnodes:(NSArray *)subnodes
|
||||||
|
identifier:(NSString *)identifier
|
||||||
{
|
{
|
||||||
ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor whiteColor]);
|
ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor whiteColor]);
|
||||||
|
|
||||||
ASLayoutSpec *layoutSpec =
|
ASLayoutSpec *layoutSpec = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:stackLayoutSpec background:backgroundNode];
|
||||||
[ASBackgroundLayoutSpec
|
|
||||||
backgroundLayoutSpecWithChild:[ASStackLayoutSpec stackLayoutSpecWithDirection:style.direction spacing:style.spacing justifyContent:style.justifyContent alignItems:style.alignItems children:children]
|
|
||||||
background:backgroundNode];
|
|
||||||
|
|
||||||
NSMutableArray *newSubnodes = [NSMutableArray arrayWithObject:backgroundNode];
|
NSMutableArray *newSubnodes = [NSMutableArray arrayWithObject:backgroundNode];
|
||||||
[newSubnodes addObjectsFromArray:subnodes];
|
[newSubnodes addObjectsFromArray:subnodes];
|
||||||
@@ -90,6 +120,8 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
|
|||||||
[self testLayoutSpec:layoutSpec sizeRange:sizeRange subnodes:newSubnodes identifier:identifier];
|
[self testLayoutSpec:layoutSpec sizeRange:sizeRange subnodes:newSubnodes identifier:identifier];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
- (void)testUnderflowBehaviors
|
- (void)testUnderflowBehaviors
|
||||||
{
|
{
|
||||||
// width 300px; height 0-300px
|
// width 300px; height 0-300px
|
||||||
@@ -522,4 +554,54 @@ static NSArray *defaultSubnodesWithSameSize(CGSize subnodeSize, BOOL flex)
|
|||||||
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
[self testStackLayoutSpecWithStyle:style sizeRange:kSize subnodes:subnodes identifier:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)testHorizontalAndVerticalAlignments
|
||||||
|
{
|
||||||
|
[self testStackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal itemsHorizontalAlignment:ASAlignmentLeft itemsVerticalAlignment:ASAlignmentTop identifier:@"horizontalTopLeft"];
|
||||||
|
[self testStackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal itemsHorizontalAlignment:ASAlignmentMiddle itemsVerticalAlignment:ASAlignmentCenter identifier:@"horizontalCenter"];
|
||||||
|
[self testStackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal itemsHorizontalAlignment:ASAlignmentRight itemsVerticalAlignment:ASAlignmentBottom identifier:@"horizontalBottomRight"];
|
||||||
|
[self testStackLayoutSpecWithDirection:ASStackLayoutDirectionVertical itemsHorizontalAlignment:ASAlignmentLeft itemsVerticalAlignment:ASAlignmentTop identifier:@"verticalTopLeft"];
|
||||||
|
[self testStackLayoutSpecWithDirection:ASStackLayoutDirectionVertical itemsHorizontalAlignment:ASAlignmentMiddle itemsVerticalAlignment:ASAlignmentCenter identifier:@"verticalCenter"];
|
||||||
|
[self testStackLayoutSpecWithDirection:ASStackLayoutDirectionVertical itemsHorizontalAlignment:ASAlignmentRight itemsVerticalAlignment:ASAlignmentBottom identifier:@"verticalBottomRight"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testDirectionChangeAfterSettingHorizontalAndVerticalAlignments
|
||||||
|
{
|
||||||
|
ASStackLayoutSpec *stackLayoutSpec = [[ASStackLayoutSpec alloc] init]; // Default direction is horizontal
|
||||||
|
stackLayoutSpec.horizontalAlignment = ASAlignmentRight;
|
||||||
|
stackLayoutSpec.verticalAlignment = ASAlignmentCenter;
|
||||||
|
XCTAssertEqual(stackLayoutSpec.alignItems, ASStackLayoutAlignItemsCenter);
|
||||||
|
XCTAssertEqual(stackLayoutSpec.justifyContent, ASStackLayoutJustifyContentEnd);
|
||||||
|
|
||||||
|
stackLayoutSpec.direction = ASStackLayoutDirectionVertical;
|
||||||
|
XCTAssertEqual(stackLayoutSpec.alignItems, ASStackLayoutAlignItemsEnd);
|
||||||
|
XCTAssertEqual(stackLayoutSpec.justifyContent, ASStackLayoutJustifyContentCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testAlignItemsAndJustifyContentRestrictionsIfHorizontalAndVerticalAlignmentsAreUsed
|
||||||
|
{
|
||||||
|
ASStackLayoutSpec *stackLayoutSpec = [[ASStackLayoutSpec alloc] init];
|
||||||
|
|
||||||
|
// No assertions should be thrown here because alignments are not used
|
||||||
|
stackLayoutSpec.alignItems = ASStackLayoutAlignItemsEnd;
|
||||||
|
stackLayoutSpec.justifyContent = ASStackLayoutJustifyContentEnd;
|
||||||
|
|
||||||
|
// Set alignments and assert that assertions are thrown
|
||||||
|
stackLayoutSpec.horizontalAlignment = ASAlignmentMiddle;
|
||||||
|
stackLayoutSpec.verticalAlignment = ASAlignmentCenter;
|
||||||
|
XCTAssertThrows(stackLayoutSpec.alignItems = ASStackLayoutAlignItemsEnd);
|
||||||
|
XCTAssertThrows(stackLayoutSpec.justifyContent = ASStackLayoutJustifyContentEnd);
|
||||||
|
|
||||||
|
// Unset alignments. alignItems and justifyContent should not be changed
|
||||||
|
stackLayoutSpec.horizontalAlignment = ASHorizontalAlignmentNone;
|
||||||
|
stackLayoutSpec.verticalAlignment = ASVerticalAlignmentNone;
|
||||||
|
XCTAssertEqual(stackLayoutSpec.alignItems, ASStackLayoutAlignItemsCenter);
|
||||||
|
XCTAssertEqual(stackLayoutSpec.justifyContent, ASStackLayoutJustifyContentCenter);
|
||||||
|
|
||||||
|
// Now that alignments are none, setting alignItems and justifyContent should be allowed again
|
||||||
|
stackLayoutSpec.alignItems = ASStackLayoutAlignItemsEnd;
|
||||||
|
stackLayoutSpec.justifyContent = ASStackLayoutJustifyContentEnd;
|
||||||
|
XCTAssertEqual(stackLayoutSpec.alignItems, ASStackLayoutAlignItemsEnd);
|
||||||
|
XCTAssertEqual(stackLayoutSpec.justifyContent, ASStackLayoutJustifyContentEnd);
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
Reference in New Issue
Block a user