|  |  |  | // | 
					
						
							|  |  |  | //  Copyright (c) 2018 Open Whisper Systems. All rights reserved. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #import "UIView+OWS.h" | 
					
						
							|  |  |  | #import "OWSMath.h" | 
					
						
							|  |  |  | #import <SignalServiceKit/AppContext.h> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NS_ASSUME_NONNULL_BEGIN | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline CGFloat ScreenShortDimension() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return MIN([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const CGFloat kIPhone5ScreenWidth = 320.f; | 
					
						
							|  |  |  | static const CGFloat kIPhone7PlusScreenWidth = 414.f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CGFloat ScaleFromIPhone5To7Plus(CGFloat iPhone5Value, CGFloat iPhone7PlusValue) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     CGFloat screenShortDimension = ScreenShortDimension(); | 
					
						
							|  |  |  |     return round(CGFloatLerp(iPhone5Value, | 
					
						
							|  |  |  |         iPhone7PlusValue, | 
					
						
							|  |  |  |         CGFloatInverseLerp(screenShortDimension, kIPhone5ScreenWidth, kIPhone7PlusScreenWidth))); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CGFloat ScaleFromIPhone5(CGFloat iPhone5Value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     CGFloat screenShortDimension = ScreenShortDimension(); | 
					
						
							|  |  |  |     return round(iPhone5Value * screenShortDimension / kIPhone5ScreenWidth); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma mark - | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @implementation UIView (OWS) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSArray<NSLayoutConstraint *> *)autoPinWidthToSuperviewWithMargin:(CGFloat)margin | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     NSArray<NSLayoutConstraint *> *result = @[ | 
					
						
							|  |  |  |         [self autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:margin], | 
					
						
							|  |  |  |         [self autoPinEdgeToSuperviewEdge:ALEdgeRight withInset:margin], | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSArray<NSLayoutConstraint *> *)autoPinWidthToSuperview | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     NSArray<NSLayoutConstraint *> *result = @[ | 
					
						
							|  |  |  |         [self autoPinEdgeToSuperviewEdge:ALEdgeLeft], | 
					
						
							|  |  |  |         [self autoPinEdgeToSuperviewEdge:ALEdgeRight], | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSArray<NSLayoutConstraint *> *)autoPinLeadingAndTrailingToSuperviewMargin | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     NSArray<NSLayoutConstraint *> *result = @[ | 
					
						
							|  |  |  |         [self autoPinLeadingToSuperviewMargin], | 
					
						
							|  |  |  |         [self autoPinTrailingToSuperviewMargin], | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSArray<NSLayoutConstraint *> *)autoPinHeightToSuperviewWithMargin:(CGFloat)margin | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     NSArray<NSLayoutConstraint *> *result = @[ | 
					
						
							|  |  |  |         [self autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:margin], | 
					
						
							|  |  |  |         [self autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:margin], | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSArray<NSLayoutConstraint *> *)autoPinHeightToSuperview | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     NSArray<NSLayoutConstraint *> *result = @[ | 
					
						
							|  |  |  |         [self autoPinEdgeToSuperviewEdge:ALEdgeTop], | 
					
						
							|  |  |  |         [self autoPinEdgeToSuperviewEdge:ALEdgeBottom], | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSArray<NSLayoutConstraint *> *)autoPinToSuperviewEdges | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     NSArray<NSLayoutConstraint *> *result = @[ | 
					
						
							|  |  |  |         [self autoPinEdgeToSuperviewEdge:ALEdgeLeft], | 
					
						
							|  |  |  |         [self autoPinEdgeToSuperviewEdge:ALEdgeRight], | 
					
						
							|  |  |  |         [self autoPinEdgeToSuperviewEdge:ALEdgeTop], | 
					
						
							|  |  |  |         [self autoPinEdgeToSuperviewEdge:ALEdgeBottom], | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSArray<NSLayoutConstraint *> *)autoPinToSuperviewMargins | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     NSArray<NSLayoutConstraint *> *result = @[ | 
					
						
							|  |  |  |         [self autoPinTopToSuperviewMargin], | 
					
						
							|  |  |  |         [self autoPinLeadingToSuperviewMargin], | 
					
						
							|  |  |  |         [self autoPinTrailingToSuperviewMargin], | 
					
						
							|  |  |  |         [self autoPinBottomToSuperviewMargin], | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoHCenterInSuperview | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return [self autoAlignAxis:ALAxisVertical toSameAxisOfView:self.superview]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoVCenterInSuperview | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return [self autoAlignAxis:ALAxisHorizontal toSameAxisOfView:self.superview]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)autoPinWidthToWidthOfView:(UIView *)view | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OWSAssert(view); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     [self autoPinEdge:ALEdgeLeft toEdge:ALEdgeLeft ofView:view]; | 
					
						
							|  |  |  |     [self autoPinEdge:ALEdgeRight toEdge:ALEdgeRight ofView:view]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)autoPinHeightToHeightOfView:(UIView *)view | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OWSAssert(view); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     [self autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:view]; | 
					
						
							|  |  |  |     [self autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:view]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinToSquareAspectRatio | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return [self autoPinToAspectRatio:1.0]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinToAspectRatio:(CGFloat)ratio | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Clamp to ensure view has reasonable aspect ratio. | 
					
						
							|  |  |  |     CGFloat clampedRatio = CGFloatClamp(ratio, 0.05, 95.0); | 
					
						
							|  |  |  |     if (clampedRatio != ratio) { | 
					
						
							|  |  |  |         OWSFail(@"Invalid aspect ratio: %f for view: %@", ratio, self); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     self.translatesAutoresizingMaskIntoConstraints = NO; | 
					
						
							|  |  |  |     NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self | 
					
						
							|  |  |  |                                                                   attribute:NSLayoutAttributeWidth | 
					
						
							|  |  |  |                                                                   relatedBy:NSLayoutRelationEqual | 
					
						
							|  |  |  |                                                                      toItem:self | 
					
						
							|  |  |  |                                                                   attribute:NSLayoutAttributeHeight | 
					
						
							|  |  |  |                                                                  multiplier:clampedRatio | 
					
						
							|  |  |  |                                                                    constant:0.f]; | 
					
						
							|  |  |  |     [constraint autoInstall]; | 
					
						
							|  |  |  |     return constraint; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma mark - Content Hugging and Compression Resistance | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)setContentHuggingLow | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self setContentHuggingHorizontalLow]; | 
					
						
							|  |  |  |     [self setContentHuggingVerticalLow]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)setContentHuggingHigh | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self setContentHuggingHorizontalHigh]; | 
					
						
							|  |  |  |     [self setContentHuggingVerticalHigh]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)setContentHuggingHorizontalLow | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self setContentHuggingPriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)setContentHuggingHorizontalHigh | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)setContentHuggingVerticalLow | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self setContentHuggingPriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisVertical]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)setContentHuggingVerticalHigh | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)setCompressionResistanceLow | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self setCompressionResistanceHorizontalLow]; | 
					
						
							|  |  |  |     [self setCompressionResistanceVerticalLow]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)setCompressionResistanceHigh | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self setCompressionResistanceHorizontalHigh]; | 
					
						
							|  |  |  |     [self setCompressionResistanceVerticalHigh]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)setCompressionResistanceHorizontalLow | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self setContentCompressionResistancePriority:0 forAxis:UILayoutConstraintAxisHorizontal]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)setCompressionResistanceHorizontalHigh | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)setCompressionResistanceVerticalLow | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self setContentCompressionResistancePriority:0 forAxis:UILayoutConstraintAxisVertical]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)setCompressionResistanceVerticalHigh | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma mark - Manual Layout | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (CGFloat)left | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return self.frame.origin.x; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (CGFloat)right | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return self.frame.origin.x + self.frame.size.width; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (CGFloat)top | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return self.frame.origin.y; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (CGFloat)bottom | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return self.frame.origin.y + self.frame.size.height; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (CGFloat)width | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return self.frame.size.width; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (CGFloat)height | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return self.frame.size.height; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)centerOnSuperview | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OWSAssert(self.superview); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     self.frame = CGRectMake(round((self.superview.width - self.width) * 0.5f), | 
					
						
							|  |  |  |         round((self.superview.height - self.height) * 0.5f), | 
					
						
							|  |  |  |         self.width, | 
					
						
							|  |  |  |         self.height); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma mark - RTL | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinLeadingToSuperviewMargin | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return [self autoPinLeadingToSuperviewMarginWithInset:0]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinLeadingToSuperviewMarginWithInset:(CGFloat)inset | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     self.translatesAutoresizingMaskIntoConstraints = NO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     NSLayoutConstraint *constraint = | 
					
						
							|  |  |  |         [self.leadingAnchor constraintEqualToAnchor:self.superview.layoutMarginsGuide.leadingAnchor constant:inset]; | 
					
						
							|  |  |  |     constraint.active = YES; | 
					
						
							|  |  |  |     return constraint; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinTrailingToSuperviewMargin | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return [self autoPinTrailingToSuperviewMarginWithInset:0]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinTrailingToSuperviewMarginWithInset:(CGFloat)inset | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     self.translatesAutoresizingMaskIntoConstraints = NO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     NSLayoutConstraint *constraint = | 
					
						
							|  |  |  |         [self.trailingAnchor constraintEqualToAnchor:self.superview.layoutMarginsGuide.trailingAnchor constant:-inset]; | 
					
						
							|  |  |  |     constraint.active = YES; | 
					
						
							|  |  |  |     return constraint; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinBottomToSuperviewMargin | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return [self autoPinBottomToSuperviewMarginWithInset:0.f]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinBottomToSuperviewMarginWithInset:(CGFloat)inset | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     self.translatesAutoresizingMaskIntoConstraints = NO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     NSLayoutConstraint *constraint = | 
					
						
							|  |  |  |         [self.bottomAnchor constraintEqualToAnchor:self.superview.layoutMarginsGuide.bottomAnchor constant:-inset]; | 
					
						
							|  |  |  |     constraint.active = YES; | 
					
						
							|  |  |  |     return constraint; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinTopToSuperviewMargin | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return [self autoPinTopToSuperviewMarginWithInset:0.f]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinTopToSuperviewMarginWithInset:(CGFloat)inset | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     self.translatesAutoresizingMaskIntoConstraints = NO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     NSLayoutConstraint *constraint = | 
					
						
							|  |  |  |         [self.topAnchor constraintEqualToAnchor:self.superview.layoutMarginsGuide.topAnchor constant:inset]; | 
					
						
							|  |  |  |     constraint.active = YES; | 
					
						
							|  |  |  |     return constraint; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinLeadingToTrailingEdgeOfView:(UIView *)view | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OWSAssert(view); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return [self autoPinLeadingToTrailingEdgeOfView:view offset:0]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinLeadingToTrailingEdgeOfView:(UIView *)view offset:(CGFloat)offset | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OWSAssert(view); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     self.translatesAutoresizingMaskIntoConstraints = NO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     NSLayoutConstraint *constraint = [self.leadingAnchor constraintEqualToAnchor:view.trailingAnchor constant:offset]; | 
					
						
							|  |  |  |     constraint.active = YES; | 
					
						
							|  |  |  |     return constraint; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinTrailingToLeadingEdgeOfView:(UIView *)view | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OWSAssert(view); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return [self autoPinTrailingToLeadingEdgeOfView:view offset:0]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinTrailingToLeadingEdgeOfView:(UIView *)view offset:(CGFloat)offset | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OWSAssert(view); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     self.translatesAutoresizingMaskIntoConstraints = NO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     NSLayoutConstraint *constraint = [self.trailingAnchor constraintEqualToAnchor:view.leadingAnchor constant:-offset]; | 
					
						
							|  |  |  |     constraint.active = YES; | 
					
						
							|  |  |  |     return constraint; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinLeadingToEdgeOfView:(UIView *)view | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OWSAssert(view); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return [self autoPinLeadingToEdgeOfView:view offset:0]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinLeadingToEdgeOfView:(UIView *)view offset:(CGFloat)offset | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OWSAssert(view); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     self.translatesAutoresizingMaskIntoConstraints = NO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     NSLayoutConstraint *constraint = [self.leadingAnchor constraintEqualToAnchor:view.leadingAnchor constant:offset]; | 
					
						
							|  |  |  |     constraint.active = YES; | 
					
						
							|  |  |  |     return constraint; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinTrailingToEdgeOfView:(UIView *)view | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OWSAssert(view); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return [self autoPinTrailingToEdgeOfView:view offset:0]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSLayoutConstraint *)autoPinTrailingToEdgeOfView:(UIView *)view offset:(CGFloat)margin | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OWSAssert(view); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     self.translatesAutoresizingMaskIntoConstraints = NO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     NSLayoutConstraint *constraint = [self.trailingAnchor constraintEqualToAnchor:view.trailingAnchor constant:margin]; | 
					
						
							|  |  |  |     constraint.active = YES; | 
					
						
							|  |  |  |     return constraint; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSTextAlignment)textAlignmentUnnatural | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return (CurrentAppContext().isRTL ? NSTextAlignmentLeft : NSTextAlignmentRight); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)setHLayoutMargins:(CGFloat)value | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     UIEdgeInsets layoutMargins = self.layoutMargins; | 
					
						
							|  |  |  |     layoutMargins.left = value; | 
					
						
							|  |  |  |     layoutMargins.right = value; | 
					
						
							|  |  |  |     self.layoutMargins = layoutMargins; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSArray<NSLayoutConstraint *> *)autoPinToEdgesOfView:(UIView *)view | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OWSAssert(view); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return @[ | 
					
						
							|  |  |  |         [self autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:view], | 
					
						
							|  |  |  |         [self autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:view], | 
					
						
							|  |  |  |         [self autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:view], | 
					
						
							|  |  |  |         [self autoPinEdge:ALEdgeTrailing toEdge:ALEdgeTrailing ofView:view], | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma mark - Containers | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | + (UIView *)containerView | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     UIView *view = [UIView new]; | 
					
						
							|  |  |  |     // Leading and trailing anchors honor layout margins. | 
					
						
							|  |  |  |     // When using a UIView as a "div" to structure layout, we don't want it to have margins. | 
					
						
							|  |  |  |     view.layoutMargins = UIEdgeInsetsZero; | 
					
						
							|  |  |  |     return view; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | + (UIView *)verticalStackWithSubviews:(NSArray<UIView *> *)subviews spacing:(int)spacing | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     UIView *container = [UIView containerView]; | 
					
						
							|  |  |  |     UIView *_Nullable lastSubview = nil; | 
					
						
							|  |  |  |     for (UIView *subview in subviews) { | 
					
						
							|  |  |  |         [container addSubview:subview]; | 
					
						
							|  |  |  |         [subview autoPinWidthToSuperview]; | 
					
						
							|  |  |  |         if (lastSubview) { | 
					
						
							|  |  |  |             [subview autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:lastSubview withOffset:spacing]; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             [subview autoPinEdgeToSuperviewEdge:ALEdgeTop]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         lastSubview = subview; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     [lastSubview autoPinEdgeToSuperviewEdge:ALEdgeBottom]; | 
					
						
							|  |  |  |     return container; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma mark - Debugging | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)addBorderWithColor:(UIColor *)color | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     self.layer.borderColor = color.CGColor; | 
					
						
							|  |  |  |     self.layer.borderWidth = 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)addRedBorder | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self addBorderWithColor:[UIColor redColor]]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)addRedBorderRecursively | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self addRedBorder]; | 
					
						
							|  |  |  |     for (UIView *subview in self.subviews) { | 
					
						
							|  |  |  |         [subview addRedBorderRecursively]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)logFrame | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self logFrameWithLabel:@""]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)logFrameWithLabel:(NSString *)label | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     DDLogVerbose(@"%@ %@ frame: %@, hidden: %d, opacity: %f, layoutMargins: %@", | 
					
						
							|  |  |  |         self.logTag, | 
					
						
							|  |  |  |         label, | 
					
						
							|  |  |  |         NSStringFromCGRect(self.frame), | 
					
						
							|  |  |  |         self.hidden, | 
					
						
							|  |  |  |         self.layer.opacity, | 
					
						
							|  |  |  |         NSStringFromUIEdgeInsets(self.layoutMargins)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)logFrameLater | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [self logFrameLaterWithLabel:@""]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)logFrameLaterWithLabel:(NSString *)label | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     dispatch_async(dispatch_get_main_queue(), ^{ | 
					
						
							|  |  |  |         [self logFrameWithLabel:label]; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)logHierarchyUpwardLaterWithLabel:(NSString *)label | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     dispatch_async(dispatch_get_main_queue(), ^{ | 
					
						
							|  |  |  |         DDLogVerbose(@"%@ %@ ----", self.logTag, label); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     UIResponder *responder = self; | 
					
						
							|  |  |  |     while (responder) { | 
					
						
							|  |  |  |         if ([responder isKindOfClass:[UIView class]]) { | 
					
						
							|  |  |  |             UIView *view = (UIView *)responder; | 
					
						
							|  |  |  |             [view logFrameLaterWithLabel:@"\t"]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         responder = responder.nextResponder; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma mark - | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @implementation UIScrollView (OWS) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)applyScrollViewInsetsFix | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Fix a bug that only affects iOS 11.0.x and 11.1.x. | 
					
						
							|  |  |  |     // The symptom is a fix weird animation that happens when using the interactive pop gesture. | 
					
						
							|  |  |  |     if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(11, 0) && !SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(11, 2)) { | 
					
						
							|  |  |  | #pragma clang diagnostic push | 
					
						
							|  |  |  | #pragma clang diagnostic ignored "-Wpartial-availability" | 
					
						
							|  |  |  |         self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; | 
					
						
							|  |  |  | #pragma clang diagnostic pop | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma mark - | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @implementation UIStackView (OWS) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)addBackgroundViewWithBackgroundColor:(UIColor *)backgroundColor | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     UIView *subview = [UIView new]; | 
					
						
							|  |  |  |     subview.backgroundColor = backgroundColor; | 
					
						
							|  |  |  |     [self addSubview:subview]; | 
					
						
							|  |  |  |     [subview autoPinEdgesToSuperviewEdges]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CGFloat CGHairlineWidth() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return 1.f / UIScreen.mainScreen.scale; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NS_ASSUME_NONNULL_END |