added iOS source code
[wl-app.git] / iOS / Pods / MBProgressHUD / MBProgressHUD.m
diff --git a/iOS/Pods/MBProgressHUD/MBProgressHUD.m b/iOS/Pods/MBProgressHUD/MBProgressHUD.m
new file mode 100644 (file)
index 0000000..1bcf9e9
--- /dev/null
@@ -0,0 +1,1495 @@
+//
+// MBProgressHUD.m
+// Version 1.1.0
+// Created by Matej Bukovinski on 2.4.09.
+//
+
+#import "MBProgressHUD.h"
+#import <tgmath.h>
+
+
+#ifndef kCFCoreFoundationVersionNumber_iOS_7_0
+    #define kCFCoreFoundationVersionNumber_iOS_7_0 847.20
+#endif
+
+#ifndef kCFCoreFoundationVersionNumber_iOS_8_0
+    #define kCFCoreFoundationVersionNumber_iOS_8_0 1129.15
+#endif
+
+#define MBMainThreadAssert() NSAssert([NSThread isMainThread], @"MBProgressHUD needs to be accessed on the main thread.");
+
+CGFloat const MBProgressMaxOffset = 1000000.f;
+
+static const CGFloat MBDefaultPadding = 4.f;
+static const CGFloat MBDefaultLabelFontSize = 16.f;
+static const CGFloat MBDefaultDetailsLabelFontSize = 12.f;
+
+
+@interface MBProgressHUD () {
+    // Deprecated
+    UIColor *_activityIndicatorColor;
+    CGFloat _opacity;
+}
+
+@property (nonatomic, assign) BOOL useAnimation;
+@property (nonatomic, assign, getter=hasFinished) BOOL finished;
+@property (nonatomic, strong) UIView *indicator;
+@property (nonatomic, strong) NSDate *showStarted;
+@property (nonatomic, strong) NSArray *paddingConstraints;
+@property (nonatomic, strong) NSArray *bezelConstraints;
+@property (nonatomic, strong) UIView *topSpacer;
+@property (nonatomic, strong) UIView *bottomSpacer;
+@property (nonatomic, weak) NSTimer *graceTimer;
+@property (nonatomic, weak) NSTimer *minShowTimer;
+@property (nonatomic, weak) NSTimer *hideDelayTimer;
+@property (nonatomic, weak) CADisplayLink *progressObjectDisplayLink;
+
+// Deprecated
+@property (assign) BOOL taskInProgress;
+
+@end
+
+
+@interface MBProgressHUDRoundedButton : UIButton
+@end
+
+
+@implementation MBProgressHUD
+
+#pragma mark - Class methods
+
++ (instancetype)showHUDAddedTo:(UIView *)view animated:(BOOL)animated {
+    MBProgressHUD *hud = [[self alloc] initWithView:view];
+    hud.removeFromSuperViewOnHide = YES;
+    [view addSubview:hud];
+    [hud showAnimated:animated];
+    return hud;
+}
+
++ (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated {
+    MBProgressHUD *hud = [self HUDForView:view];
+    if (hud != nil) {
+        hud.removeFromSuperViewOnHide = YES;
+        [hud hideAnimated:animated];
+        return YES;
+    }
+    return NO;
+}
+
++ (MBProgressHUD *)HUDForView:(UIView *)view {
+    NSEnumerator *subviewsEnum = [view.subviews reverseObjectEnumerator];
+    for (UIView *subview in subviewsEnum) {
+        if ([subview isKindOfClass:self]) {
+            MBProgressHUD *hud = (MBProgressHUD *)subview;
+            if (hud.hasFinished == NO) {
+                return hud;
+            }
+        }
+    }
+    return nil;
+}
+
+#pragma mark - Lifecycle
+
+- (void)commonInit {
+    // Set default values for properties
+    _animationType = MBProgressHUDAnimationFade;
+    _mode = MBProgressHUDModeIndeterminate;
+    _margin = 20.0f;
+    _opacity = 1.f;
+    _defaultMotionEffectsEnabled = YES;
+
+    // Default color, depending on the current iOS version
+    BOOL isLegacy = kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_7_0;
+    _contentColor = isLegacy ? [UIColor whiteColor] : [UIColor colorWithWhite:0.f alpha:0.7f];
+    // Transparent background
+    self.opaque = NO;
+    self.backgroundColor = [UIColor clearColor];
+    // Make it invisible for now
+    self.alpha = 0.0f;
+    self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+    self.layer.allowsGroupOpacity = NO;
+
+    [self setupViews];
+    [self updateIndicators];
+    [self registerForNotifications];
+}
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    if ((self = [super initWithFrame:frame])) {
+        [self commonInit];
+    }
+    return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder {
+    if ((self = [super initWithCoder:aDecoder])) {
+        [self commonInit];
+    }
+    return self;
+}
+
+- (id)initWithView:(UIView *)view {
+    NSAssert(view, @"View must not be nil.");
+    return [self initWithFrame:view.bounds];
+}
+
+- (void)dealloc {
+    [self unregisterFromNotifications];
+}
+
+#pragma mark - Show & hide
+
+- (void)showAnimated:(BOOL)animated {
+    MBMainThreadAssert();
+    [self.minShowTimer invalidate];
+    self.useAnimation = animated;
+    self.finished = NO;
+    // If the grace time is set, postpone the HUD display
+    if (self.graceTime > 0.0) {
+        NSTimer *timer = [NSTimer timerWithTimeInterval:self.graceTime target:self selector:@selector(handleGraceTimer:) userInfo:nil repeats:NO];
+        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
+        self.graceTimer = timer;
+    } 
+    // ... otherwise show the HUD immediately
+    else {
+        [self showUsingAnimation:self.useAnimation];
+    }
+}
+
+- (void)hideAnimated:(BOOL)animated {
+    MBMainThreadAssert();
+    [self.graceTimer invalidate];
+    self.useAnimation = animated;
+    self.finished = YES;
+    // If the minShow time is set, calculate how long the HUD was shown,
+    // and postpone the hiding operation if necessary
+    if (self.minShowTime > 0.0 && self.showStarted) {
+        NSTimeInterval interv = [[NSDate date] timeIntervalSinceDate:self.showStarted];
+        if (interv < self.minShowTime) {
+            NSTimer *timer = [NSTimer timerWithTimeInterval:(self.minShowTime - interv) target:self selector:@selector(handleMinShowTimer:) userInfo:nil repeats:NO];
+            [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
+            self.minShowTimer = timer;
+            return;
+        } 
+    }
+    // ... otherwise hide the HUD immediately
+    [self hideUsingAnimation:self.useAnimation];
+}
+
+- (void)hideAnimated:(BOOL)animated afterDelay:(NSTimeInterval)delay {
+    // Cancel any scheduled hideDelayed: calls
+    [self.hideDelayTimer invalidate];
+
+    NSTimer *timer = [NSTimer timerWithTimeInterval:delay target:self selector:@selector(handleHideTimer:) userInfo:@(animated) repeats:NO];
+    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
+    self.hideDelayTimer = timer;
+}
+
+#pragma mark - Timer callbacks
+
+- (void)handleGraceTimer:(NSTimer *)theTimer {
+    // Show the HUD only if the task is still running
+    if (!self.hasFinished) {
+        [self showUsingAnimation:self.useAnimation];
+    }
+}
+
+- (void)handleMinShowTimer:(NSTimer *)theTimer {
+    [self hideUsingAnimation:self.useAnimation];
+}
+
+- (void)handleHideTimer:(NSTimer *)timer {
+    [self hideAnimated:[timer.userInfo boolValue]];
+}
+
+#pragma mark - View Hierrarchy
+
+- (void)didMoveToSuperview {
+    [self updateForCurrentOrientationAnimated:NO];
+}
+
+#pragma mark - Internal show & hide operations
+
+- (void)showUsingAnimation:(BOOL)animated {
+    // Cancel any previous animations
+    [self.bezelView.layer removeAllAnimations];
+    [self.backgroundView.layer removeAllAnimations];
+
+    // Cancel any scheduled hideDelayed: calls
+    [self.hideDelayTimer invalidate];
+
+    self.showStarted = [NSDate date];
+    self.alpha = 1.f;
+
+    // Needed in case we hide and re-show with the same NSProgress object attached.
+    [self setNSProgressDisplayLinkEnabled:YES];
+
+    if (animated) {
+        [self animateIn:YES withType:self.animationType completion:NULL];
+    } else {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+        self.bezelView.alpha = self.opacity;
+#pragma clang diagnostic pop
+        self.backgroundView.alpha = 1.f;
+    }
+}
+
+- (void)hideUsingAnimation:(BOOL)animated {
+    if (animated && self.showStarted) {
+        self.showStarted = nil;
+        [self animateIn:NO withType:self.animationType completion:^(BOOL finished) {
+            [self done];
+        }];
+    } else {
+        self.showStarted = nil;
+        self.bezelView.alpha = 0.f;
+        self.backgroundView.alpha = 1.f;
+        [self done];
+    }
+}
+
+- (void)animateIn:(BOOL)animatingIn withType:(MBProgressHUDAnimation)type completion:(void(^)(BOOL finished))completion {
+    // Automatically determine the correct zoom animation type
+    if (type == MBProgressHUDAnimationZoom) {
+        type = animatingIn ? MBProgressHUDAnimationZoomIn : MBProgressHUDAnimationZoomOut;
+    }
+
+    CGAffineTransform small = CGAffineTransformMakeScale(0.5f, 0.5f);
+    CGAffineTransform large = CGAffineTransformMakeScale(1.5f, 1.5f);
+
+    // Set starting state
+    UIView *bezelView = self.bezelView;
+    if (animatingIn && bezelView.alpha == 0.f && type == MBProgressHUDAnimationZoomIn) {
+        bezelView.transform = small;
+    } else if (animatingIn && bezelView.alpha == 0.f && type == MBProgressHUDAnimationZoomOut) {
+        bezelView.transform = large;
+    }
+
+    // Perform animations
+    dispatch_block_t animations = ^{
+        if (animatingIn) {
+            bezelView.transform = CGAffineTransformIdentity;
+        } else if (!animatingIn && type == MBProgressHUDAnimationZoomIn) {
+            bezelView.transform = large;
+        } else if (!animatingIn && type == MBProgressHUDAnimationZoomOut) {
+            bezelView.transform = small;
+        }
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+        bezelView.alpha = animatingIn ? self.opacity : 0.f;
+#pragma clang diagnostic pop
+        self.backgroundView.alpha = animatingIn ? 1.f : 0.f;
+    };
+
+    // Spring animations are nicer, but only available on iOS 7+
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 || TARGET_OS_TV
+    if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_7_0) {
+        [UIView animateWithDuration:0.3 delay:0. usingSpringWithDamping:1.f initialSpringVelocity:0.f options:UIViewAnimationOptionBeginFromCurrentState animations:animations completion:completion];
+        return;
+    }
+#endif
+    [UIView animateWithDuration:0.3 delay:0. options:UIViewAnimationOptionBeginFromCurrentState animations:animations completion:completion];
+}
+
+- (void)done {
+    // Cancel any scheduled hideDelayed: calls
+    [self.hideDelayTimer invalidate];
+    [self setNSProgressDisplayLinkEnabled:NO];
+
+    if (self.hasFinished) {
+        self.alpha = 0.0f;
+        if (self.removeFromSuperViewOnHide) {
+            [self removeFromSuperview];
+        }
+    }
+    MBProgressHUDCompletionBlock completionBlock = self.completionBlock;
+    if (completionBlock) {
+        completionBlock();
+    }
+    id<MBProgressHUDDelegate> delegate = self.delegate;
+    if ([delegate respondsToSelector:@selector(hudWasHidden:)]) {
+        [delegate performSelector:@selector(hudWasHidden:) withObject:self];
+    }
+}
+
+#pragma mark - UI
+
+- (void)setupViews {
+    UIColor *defaultColor = self.contentColor;
+
+    MBBackgroundView *backgroundView = [[MBBackgroundView alloc] initWithFrame:self.bounds];
+    backgroundView.style = MBProgressHUDBackgroundStyleSolidColor;
+    backgroundView.backgroundColor = [UIColor clearColor];
+    backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+    backgroundView.alpha = 0.f;
+    [self addSubview:backgroundView];
+    _backgroundView = backgroundView;
+
+    MBBackgroundView *bezelView = [MBBackgroundView new];
+    bezelView.translatesAutoresizingMaskIntoConstraints = NO;
+    bezelView.layer.cornerRadius = 5.f;
+    bezelView.alpha = 0.f;
+    [self addSubview:bezelView];
+    _bezelView = bezelView;
+    [self updateBezelMotionEffects];
+
+    UILabel *label = [UILabel new];
+    label.adjustsFontSizeToFitWidth = NO;
+    label.textAlignment = NSTextAlignmentCenter;
+    label.textColor = defaultColor;
+    label.font = [UIFont boldSystemFontOfSize:MBDefaultLabelFontSize];
+    label.opaque = NO;
+    label.backgroundColor = [UIColor clearColor];
+    _label = label;
+
+    UILabel *detailsLabel = [UILabel new];
+    detailsLabel.adjustsFontSizeToFitWidth = NO;
+    detailsLabel.textAlignment = NSTextAlignmentCenter;
+    detailsLabel.textColor = defaultColor;
+    detailsLabel.numberOfLines = 0;
+    detailsLabel.font = [UIFont boldSystemFontOfSize:MBDefaultDetailsLabelFontSize];
+    detailsLabel.opaque = NO;
+    detailsLabel.backgroundColor = [UIColor clearColor];
+    _detailsLabel = detailsLabel;
+
+    UIButton *button = [MBProgressHUDRoundedButton buttonWithType:UIButtonTypeCustom];
+    button.titleLabel.textAlignment = NSTextAlignmentCenter;
+    button.titleLabel.font = [UIFont boldSystemFontOfSize:MBDefaultDetailsLabelFontSize];
+    [button setTitleColor:defaultColor forState:UIControlStateNormal];
+    _button = button;
+
+    for (UIView *view in @[label, detailsLabel, button]) {
+        view.translatesAutoresizingMaskIntoConstraints = NO;
+        [view setContentCompressionResistancePriority:998.f forAxis:UILayoutConstraintAxisHorizontal];
+        [view setContentCompressionResistancePriority:998.f forAxis:UILayoutConstraintAxisVertical];
+        [bezelView addSubview:view];
+    }
+
+    UIView *topSpacer = [UIView new];
+    topSpacer.translatesAutoresizingMaskIntoConstraints = NO;
+    topSpacer.hidden = YES;
+    [bezelView addSubview:topSpacer];
+    _topSpacer = topSpacer;
+
+    UIView *bottomSpacer = [UIView new];
+    bottomSpacer.translatesAutoresizingMaskIntoConstraints = NO;
+    bottomSpacer.hidden = YES;
+    [bezelView addSubview:bottomSpacer];
+    _bottomSpacer = bottomSpacer;
+}
+
+- (void)updateIndicators {
+    UIView *indicator = self.indicator;
+    BOOL isActivityIndicator = [indicator isKindOfClass:[UIActivityIndicatorView class]];
+    BOOL isRoundIndicator = [indicator isKindOfClass:[MBRoundProgressView class]];
+
+    MBProgressHUDMode mode = self.mode;
+    if (mode == MBProgressHUDModeIndeterminate) {
+        if (!isActivityIndicator) {
+            // Update to indeterminate indicator
+            [indicator removeFromSuperview];
+            indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
+            [(UIActivityIndicatorView *)indicator startAnimating];
+            [self.bezelView addSubview:indicator];
+        }
+    }
+    else if (mode == MBProgressHUDModeDeterminateHorizontalBar) {
+        // Update to bar determinate indicator
+        [indicator removeFromSuperview];
+        indicator = [[MBBarProgressView alloc] init];
+        [self.bezelView addSubview:indicator];
+    }
+    else if (mode == MBProgressHUDModeDeterminate || mode == MBProgressHUDModeAnnularDeterminate) {
+        if (!isRoundIndicator) {
+            // Update to determinante indicator
+            [indicator removeFromSuperview];
+            indicator = [[MBRoundProgressView alloc] init];
+            [self.bezelView addSubview:indicator];
+        }
+        if (mode == MBProgressHUDModeAnnularDeterminate) {
+            [(MBRoundProgressView *)indicator setAnnular:YES];
+        }
+    } 
+    else if (mode == MBProgressHUDModeCustomView && self.customView != indicator) {
+        // Update custom view indicator
+        [indicator removeFromSuperview];
+        indicator = self.customView;
+        [self.bezelView addSubview:indicator];
+    }
+    else if (mode == MBProgressHUDModeText) {
+        [indicator removeFromSuperview];
+        indicator = nil;
+    }
+    indicator.translatesAutoresizingMaskIntoConstraints = NO;
+    self.indicator = indicator;
+
+    if ([indicator respondsToSelector:@selector(setProgress:)]) {
+        [(id)indicator setValue:@(self.progress) forKey:@"progress"];
+    }
+
+    [indicator setContentCompressionResistancePriority:998.f forAxis:UILayoutConstraintAxisHorizontal];
+    [indicator setContentCompressionResistancePriority:998.f forAxis:UILayoutConstraintAxisVertical];
+
+    [self updateViewsForColor:self.contentColor];
+    [self setNeedsUpdateConstraints];
+}
+
+- (void)updateViewsForColor:(UIColor *)color {
+    if (!color) return;
+
+    self.label.textColor = color;
+    self.detailsLabel.textColor = color;
+    [self.button setTitleColor:color forState:UIControlStateNormal];
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+    if (self.activityIndicatorColor) {
+        color = self.activityIndicatorColor;
+    }
+#pragma clang diagnostic pop
+
+    // UIAppearance settings are prioritized. If they are preset the set color is ignored.
+
+    UIView *indicator = self.indicator;
+    if ([indicator isKindOfClass:[UIActivityIndicatorView class]]) {
+        UIActivityIndicatorView *appearance = nil;
+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 90000
+        appearance = [UIActivityIndicatorView appearanceWhenContainedIn:[MBProgressHUD class], nil];
+#else
+        // For iOS 9+
+        appearance = [UIActivityIndicatorView appearanceWhenContainedInInstancesOfClasses:@[[MBProgressHUD class]]];
+#endif
+        
+        if (appearance.color == nil) {
+            ((UIActivityIndicatorView *)indicator).color = color;
+        }
+    } else if ([indicator isKindOfClass:[MBRoundProgressView class]]) {
+        MBRoundProgressView *appearance = nil;
+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 90000
+        appearance = [MBRoundProgressView appearanceWhenContainedIn:[MBProgressHUD class], nil];
+#else
+        appearance = [MBRoundProgressView appearanceWhenContainedInInstancesOfClasses:@[[MBProgressHUD class]]];
+#endif
+        if (appearance.progressTintColor == nil) {
+            ((MBRoundProgressView *)indicator).progressTintColor = color;
+        }
+        if (appearance.backgroundTintColor == nil) {
+            ((MBRoundProgressView *)indicator).backgroundTintColor = [color colorWithAlphaComponent:0.1];
+        }
+    } else if ([indicator isKindOfClass:[MBBarProgressView class]]) {
+        MBBarProgressView *appearance = nil;
+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 90000
+        appearance = [MBBarProgressView appearanceWhenContainedIn:[MBProgressHUD class], nil];
+#else
+        appearance = [MBBarProgressView appearanceWhenContainedInInstancesOfClasses:@[[MBProgressHUD class]]];
+#endif
+        if (appearance.progressColor == nil) {
+            ((MBBarProgressView *)indicator).progressColor = color;
+        }
+        if (appearance.lineColor == nil) {
+            ((MBBarProgressView *)indicator).lineColor = color;
+        }
+    } else {
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 || TARGET_OS_TV
+        if ([indicator respondsToSelector:@selector(setTintColor:)]) {
+            [indicator setTintColor:color];
+        }
+#endif
+    }
+}
+
+- (void)updateBezelMotionEffects {
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 || TARGET_OS_TV
+    MBBackgroundView *bezelView = self.bezelView;
+    if (![bezelView respondsToSelector:@selector(addMotionEffect:)]) return;
+
+    if (self.defaultMotionEffectsEnabled) {
+        CGFloat effectOffset = 10.f;
+        UIInterpolatingMotionEffect *effectX = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
+        effectX.maximumRelativeValue = @(effectOffset);
+        effectX.minimumRelativeValue = @(-effectOffset);
+
+        UIInterpolatingMotionEffect *effectY = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
+        effectY.maximumRelativeValue = @(effectOffset);
+        effectY.minimumRelativeValue = @(-effectOffset);
+
+        UIMotionEffectGroup *group = [[UIMotionEffectGroup alloc] init];
+        group.motionEffects = @[effectX, effectY];
+
+        [bezelView addMotionEffect:group];
+    } else {
+        NSArray *effects = [bezelView motionEffects];
+        for (UIMotionEffect *effect in effects) {
+            [bezelView removeMotionEffect:effect];
+        }
+    }
+#endif
+}
+
+#pragma mark - Layout
+
+- (void)updateConstraints {
+    UIView *bezel = self.bezelView;
+    UIView *topSpacer = self.topSpacer;
+    UIView *bottomSpacer = self.bottomSpacer;
+    CGFloat margin = self.margin;
+    NSMutableArray *bezelConstraints = [NSMutableArray array];
+    NSDictionary *metrics = @{@"margin": @(margin)};
+
+    NSMutableArray *subviews = [NSMutableArray arrayWithObjects:self.topSpacer, self.label, self.detailsLabel, self.button, self.bottomSpacer, nil];
+    if (self.indicator) [subviews insertObject:self.indicator atIndex:1];
+
+    // Remove existing constraints
+    [self removeConstraints:self.constraints];
+    [topSpacer removeConstraints:topSpacer.constraints];
+    [bottomSpacer removeConstraints:bottomSpacer.constraints];
+    if (self.bezelConstraints) {
+        [bezel removeConstraints:self.bezelConstraints];
+        self.bezelConstraints = nil;
+    }
+
+    // Center bezel in container (self), applying the offset if set
+    CGPoint offset = self.offset;
+    NSMutableArray *centeringConstraints = [NSMutableArray array];
+    [centeringConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.f constant:offset.x]];
+    [centeringConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.f constant:offset.y]];
+    [self applyPriority:998.f toConstraints:centeringConstraints];
+    [self addConstraints:centeringConstraints];
+
+    // Ensure minimum side margin is kept
+    NSMutableArray *sideConstraints = [NSMutableArray array];
+    [sideConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"|-(>=margin)-[bezel]-(>=margin)-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(bezel)]];
+    [sideConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=margin)-[bezel]-(>=margin)-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(bezel)]];
+    [self applyPriority:999.f toConstraints:sideConstraints];
+    [self addConstraints:sideConstraints];
+
+    // Minimum bezel size, if set
+    CGSize minimumSize = self.minSize;
+    if (!CGSizeEqualToSize(minimumSize, CGSizeZero)) {
+        NSMutableArray *minSizeConstraints = [NSMutableArray array];
+        [minSizeConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:minimumSize.width]];
+        [minSizeConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:minimumSize.height]];
+        [self applyPriority:997.f toConstraints:minSizeConstraints];
+        [bezelConstraints addObjectsFromArray:minSizeConstraints];
+    }
+
+    // Square aspect ratio, if set
+    if (self.square) {
+        NSLayoutConstraint *square = [NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeWidth multiplier:1.f constant:0];
+        square.priority = 997.f;
+        [bezelConstraints addObject:square];
+    }
+
+    // Top and bottom spacing
+    [topSpacer addConstraint:[NSLayoutConstraint constraintWithItem:topSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:margin]];
+    [bottomSpacer addConstraint:[NSLayoutConstraint constraintWithItem:bottomSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:margin]];
+    // Top and bottom spaces should be equal
+    [bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:topSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:bottomSpacer attribute:NSLayoutAttributeHeight multiplier:1.f constant:0.f]];
+
+    // Layout subviews in bezel
+    NSMutableArray *paddingConstraints = [NSMutableArray new];
+    [subviews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) {
+        // Center in bezel
+        [bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeCenterX multiplier:1.f constant:0.f]];
+        // Ensure the minimum edge margin is kept
+        [bezelConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"|-(>=margin)-[view]-(>=margin)-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(view)]];
+        // Element spacing
+        if (idx == 0) {
+            // First, ensure spacing to bezel edge
+            [bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeTop multiplier:1.f constant:0.f]];
+        } else if (idx == subviews.count - 1) {
+            // Last, ensure spacing to bezel edge
+            [bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeBottom multiplier:1.f constant:0.f]];
+        }
+        if (idx > 0) {
+            // Has previous
+            NSLayoutConstraint *padding = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:subviews[idx - 1] attribute:NSLayoutAttributeBottom multiplier:1.f constant:0.f];
+            [bezelConstraints addObject:padding];
+            [paddingConstraints addObject:padding];
+        }
+    }];
+
+    [bezel addConstraints:bezelConstraints];
+    self.bezelConstraints = bezelConstraints;
+    
+    self.paddingConstraints = [paddingConstraints copy];
+    [self updatePaddingConstraints];
+    
+    [super updateConstraints];
+}
+
+- (void)layoutSubviews {
+    // There is no need to update constraints if they are going to
+    // be recreated in [super layoutSubviews] due to needsUpdateConstraints being set.
+    // This also avoids an issue on iOS 8, where updatePaddingConstraints
+    // would trigger a zombie object access.
+    if (!self.needsUpdateConstraints) {
+        [self updatePaddingConstraints];
+    }
+    [super layoutSubviews];
+}
+
+- (void)updatePaddingConstraints {
+    // Set padding dynamically, depending on whether the view is visible or not
+    __block BOOL hasVisibleAncestors = NO;
+    [self.paddingConstraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *padding, NSUInteger idx, BOOL *stop) {
+        UIView *firstView = (UIView *)padding.firstItem;
+        UIView *secondView = (UIView *)padding.secondItem;
+        BOOL firstVisible = !firstView.hidden && !CGSizeEqualToSize(firstView.intrinsicContentSize, CGSizeZero);
+        BOOL secondVisible = !secondView.hidden && !CGSizeEqualToSize(secondView.intrinsicContentSize, CGSizeZero);
+        // Set if both views are visible or if there's a visible view on top that doesn't have padding
+        // added relative to the current view yet
+        padding.constant = (firstVisible && (secondVisible || hasVisibleAncestors)) ? MBDefaultPadding : 0.f;
+        hasVisibleAncestors |= secondVisible;
+    }];
+}
+
+- (void)applyPriority:(UILayoutPriority)priority toConstraints:(NSArray *)constraints {
+    for (NSLayoutConstraint *constraint in constraints) {
+        constraint.priority = priority;
+    }
+}
+
+#pragma mark - Properties
+
+- (void)setMode:(MBProgressHUDMode)mode {
+    if (mode != _mode) {
+        _mode = mode;
+        [self updateIndicators];
+    }
+}
+
+- (void)setCustomView:(UIView *)customView {
+    if (customView != _customView) {
+        _customView = customView;
+        if (self.mode == MBProgressHUDModeCustomView) {
+            [self updateIndicators];
+        }
+    }
+}
+
+- (void)setOffset:(CGPoint)offset {
+    if (!CGPointEqualToPoint(offset, _offset)) {
+        _offset = offset;
+        [self setNeedsUpdateConstraints];
+    }
+}
+
+- (void)setMargin:(CGFloat)margin {
+    if (margin != _margin) {
+        _margin = margin;
+        [self setNeedsUpdateConstraints];
+    }
+}
+
+- (void)setMinSize:(CGSize)minSize {
+    if (!CGSizeEqualToSize(minSize, _minSize)) {
+        _minSize = minSize;
+        [self setNeedsUpdateConstraints];
+    }
+}
+
+- (void)setSquare:(BOOL)square {
+    if (square != _square) {
+        _square = square;
+        [self setNeedsUpdateConstraints];
+    }
+}
+
+- (void)setProgressObjectDisplayLink:(CADisplayLink *)progressObjectDisplayLink {
+    if (progressObjectDisplayLink != _progressObjectDisplayLink) {
+        [_progressObjectDisplayLink invalidate];
+        
+        _progressObjectDisplayLink = progressObjectDisplayLink;
+        
+        [_progressObjectDisplayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
+    }
+}
+
+- (void)setProgressObject:(NSProgress *)progressObject {
+    if (progressObject != _progressObject) {
+        _progressObject = progressObject;
+        [self setNSProgressDisplayLinkEnabled:YES];
+    }
+}
+
+- (void)setProgress:(float)progress {
+    if (progress != _progress) {
+        _progress = progress;
+        UIView *indicator = self.indicator;
+        if ([indicator respondsToSelector:@selector(setProgress:)]) {
+            [(id)indicator setValue:@(self.progress) forKey:@"progress"];
+        }
+    }
+}
+
+- (void)setContentColor:(UIColor *)contentColor {
+    if (contentColor != _contentColor && ![contentColor isEqual:_contentColor]) {
+        _contentColor = contentColor;
+        [self updateViewsForColor:contentColor];
+    }
+}
+
+- (void)setDefaultMotionEffectsEnabled:(BOOL)defaultMotionEffectsEnabled {
+    if (defaultMotionEffectsEnabled != _defaultMotionEffectsEnabled) {
+        _defaultMotionEffectsEnabled = defaultMotionEffectsEnabled;
+        [self updateBezelMotionEffects];
+    }
+}
+
+#pragma mark - NSProgress
+
+- (void)setNSProgressDisplayLinkEnabled:(BOOL)enabled {
+    // We're using CADisplayLink, because NSProgress can change very quickly and observing it may starve the main thread,
+    // so we're refreshing the progress only every frame draw
+    if (enabled && self.progressObject) {
+        // Only create if not already active.
+        if (!self.progressObjectDisplayLink) {
+            self.progressObjectDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateProgressFromProgressObject)];
+        }
+    } else {
+        self.progressObjectDisplayLink = nil;
+    }
+}
+
+- (void)updateProgressFromProgressObject {
+    self.progress = self.progressObject.fractionCompleted;
+}
+
+#pragma mark - Notifications
+
+- (void)registerForNotifications {
+#if !TARGET_OS_TV
+    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+
+    [nc addObserver:self selector:@selector(statusBarOrientationDidChange:)
+               name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
+#endif
+}
+
+- (void)unregisterFromNotifications {
+#if !TARGET_OS_TV
+    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+    [nc removeObserver:self name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
+#endif
+}
+
+#if !TARGET_OS_TV
+- (void)statusBarOrientationDidChange:(NSNotification *)notification {
+    UIView *superview = self.superview;
+    if (!superview) {
+        return;
+    } else {
+        [self updateForCurrentOrientationAnimated:YES];
+    }
+}
+#endif
+
+- (void)updateForCurrentOrientationAnimated:(BOOL)animated {
+    // Stay in sync with the superview in any case
+    if (self.superview) {
+        self.frame = self.superview.bounds;
+    }
+
+    // Not needed on iOS 8+, compile out when the deployment target allows,
+    // to avoid sharedApplication problems on extension targets
+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000
+    // Only needed pre iOS 8 when added to a window
+    BOOL iOS8OrLater = kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_8_0;
+    if (iOS8OrLater || ![self.superview isKindOfClass:[UIWindow class]]) return;
+
+    // Make extension friendly. Will not get called on extensions (iOS 8+) due to the above check.
+    // This just ensures we don't get a warning about extension-unsafe API.
+    Class UIApplicationClass = NSClassFromString(@"UIApplication");
+    if (!UIApplicationClass || ![UIApplicationClass respondsToSelector:@selector(sharedApplication)]) return;
+
+    UIApplication *application = [UIApplication performSelector:@selector(sharedApplication)];
+    UIInterfaceOrientation orientation = application.statusBarOrientation;
+    CGFloat radians = 0;
+    
+    if (UIInterfaceOrientationIsLandscape(orientation)) {
+        radians = orientation == UIInterfaceOrientationLandscapeLeft ? -(CGFloat)M_PI_2 : (CGFloat)M_PI_2;
+        // Window coordinates differ!
+        self.bounds = CGRectMake(0, 0, self.bounds.size.height, self.bounds.size.width);
+    } else {
+        radians = orientation == UIInterfaceOrientationPortraitUpsideDown ? (CGFloat)M_PI : 0.f;
+    }
+
+    if (animated) {
+        [UIView animateWithDuration:0.3 animations:^{
+            self.transform = CGAffineTransformMakeRotation(radians);
+        }];
+    } else {
+        self.transform = CGAffineTransformMakeRotation(radians);
+    }
+#endif
+}
+
+@end
+
+
+@implementation MBRoundProgressView
+
+#pragma mark - Lifecycle
+
+- (id)init {
+    return [self initWithFrame:CGRectMake(0.f, 0.f, 37.f, 37.f)];
+}
+
+- (id)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        self.backgroundColor = [UIColor clearColor];
+        self.opaque = NO;
+        _progress = 0.f;
+        _annular = NO;
+        _progressTintColor = [[UIColor alloc] initWithWhite:1.f alpha:1.f];
+        _backgroundTintColor = [[UIColor alloc] initWithWhite:1.f alpha:.1f];
+    }
+    return self;
+}
+
+#pragma mark - Layout
+
+- (CGSize)intrinsicContentSize {
+    return CGSizeMake(37.f, 37.f);
+}
+
+#pragma mark - Properties
+
+- (void)setProgress:(float)progress {
+    if (progress != _progress) {
+        _progress = progress;
+        [self setNeedsDisplay];
+    }
+}
+
+- (void)setProgressTintColor:(UIColor *)progressTintColor {
+    NSAssert(progressTintColor, @"The color should not be nil.");
+    if (progressTintColor != _progressTintColor && ![progressTintColor isEqual:_progressTintColor]) {
+        _progressTintColor = progressTintColor;
+        [self setNeedsDisplay];
+    }
+}
+
+- (void)setBackgroundTintColor:(UIColor *)backgroundTintColor {
+    NSAssert(backgroundTintColor, @"The color should not be nil.");
+    if (backgroundTintColor != _backgroundTintColor && ![backgroundTintColor isEqual:_backgroundTintColor]) {
+        _backgroundTintColor = backgroundTintColor;
+        [self setNeedsDisplay];
+    }
+}
+
+#pragma mark - Drawing
+
+- (void)drawRect:(CGRect)rect {
+    CGContextRef context = UIGraphicsGetCurrentContext();
+    BOOL isPreiOS7 = kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_7_0;
+
+    if (_annular) {
+        // Draw background
+        CGFloat lineWidth = isPreiOS7 ? 5.f : 2.f;
+        UIBezierPath *processBackgroundPath = [UIBezierPath bezierPath];
+        processBackgroundPath.lineWidth = lineWidth;
+        processBackgroundPath.lineCapStyle = kCGLineCapButt;
+        CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
+        CGFloat radius = (self.bounds.size.width - lineWidth)/2;
+        CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees
+        CGFloat endAngle = (2 * (float)M_PI) + startAngle;
+        [processBackgroundPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
+        [_backgroundTintColor set];
+        [processBackgroundPath stroke];
+        // Draw progress
+        UIBezierPath *processPath = [UIBezierPath bezierPath];
+        processPath.lineCapStyle = isPreiOS7 ? kCGLineCapRound : kCGLineCapSquare;
+        processPath.lineWidth = lineWidth;
+        endAngle = (self.progress * 2 * (float)M_PI) + startAngle;
+        [processPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
+        [_progressTintColor set];
+        [processPath stroke];
+    } else {
+        // Draw background
+        CGFloat lineWidth = 2.f;
+        CGRect allRect = self.bounds;
+        CGRect circleRect = CGRectInset(allRect, lineWidth/2.f, lineWidth/2.f);
+        CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
+        [_progressTintColor setStroke];
+        [_backgroundTintColor setFill];
+        CGContextSetLineWidth(context, lineWidth);
+        if (isPreiOS7) {
+            CGContextFillEllipseInRect(context, circleRect);
+        }
+        CGContextStrokeEllipseInRect(context, circleRect);
+        // 90 degrees
+        CGFloat startAngle = - ((float)M_PI / 2.f);
+        // Draw progress
+        if (isPreiOS7) {
+            CGFloat radius = (CGRectGetWidth(self.bounds) / 2.f) - lineWidth;
+            CGFloat endAngle = (self.progress * 2.f * (float)M_PI) + startAngle;
+            [_progressTintColor setFill];
+            CGContextMoveToPoint(context, center.x, center.y);
+            CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0);
+            CGContextClosePath(context);
+            CGContextFillPath(context);
+        } else {
+            UIBezierPath *processPath = [UIBezierPath bezierPath];
+            processPath.lineCapStyle = kCGLineCapButt;
+            processPath.lineWidth = lineWidth * 2.f;
+            CGFloat radius = (CGRectGetWidth(self.bounds) / 2.f) - (processPath.lineWidth / 2.f);
+            CGFloat endAngle = (self.progress * 2.f * (float)M_PI) + startAngle;
+            [processPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
+            // Ensure that we don't get color overlapping when _progressTintColor alpha < 1.f.
+            CGContextSetBlendMode(context, kCGBlendModeCopy);
+            [_progressTintColor set];
+            [processPath stroke];
+        }
+    }
+}
+
+@end
+
+
+@implementation MBBarProgressView
+
+#pragma mark - Lifecycle
+
+- (id)init {
+    return [self initWithFrame:CGRectMake(.0f, .0f, 120.0f, 20.0f)];
+}
+
+- (id)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        _progress = 0.f;
+        _lineColor = [UIColor whiteColor];
+        _progressColor = [UIColor whiteColor];
+        _progressRemainingColor = [UIColor clearColor];
+        self.backgroundColor = [UIColor clearColor];
+        self.opaque = NO;
+    }
+    return self;
+}
+
+#pragma mark - Layout
+
+- (CGSize)intrinsicContentSize {
+    BOOL isPreiOS7 = kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_7_0;
+    return CGSizeMake(120.f, isPreiOS7 ? 20.f : 10.f);
+}
+
+#pragma mark - Properties
+
+- (void)setProgress:(float)progress {
+    if (progress != _progress) {
+        _progress = progress;
+        [self setNeedsDisplay];
+    }
+}
+
+- (void)setProgressColor:(UIColor *)progressColor {
+    NSAssert(progressColor, @"The color should not be nil.");
+    if (progressColor != _progressColor && ![progressColor isEqual:_progressColor]) {
+        _progressColor = progressColor;
+        [self setNeedsDisplay];
+    }
+}
+
+- (void)setProgressRemainingColor:(UIColor *)progressRemainingColor {
+    NSAssert(progressRemainingColor, @"The color should not be nil.");
+    if (progressRemainingColor != _progressRemainingColor && ![progressRemainingColor isEqual:_progressRemainingColor]) {
+        _progressRemainingColor = progressRemainingColor;
+        [self setNeedsDisplay];
+    }
+}
+
+#pragma mark - Drawing
+
+- (void)drawRect:(CGRect)rect {
+    CGContextRef context = UIGraphicsGetCurrentContext();
+    
+    CGContextSetLineWidth(context, 2);
+    CGContextSetStrokeColorWithColor(context,[_lineColor CGColor]);
+    CGContextSetFillColorWithColor(context, [_progressRemainingColor CGColor]);
+    
+    // Draw background and Border
+    CGFloat radius = (rect.size.height / 2) - 2;
+    CGContextMoveToPoint(context, 2, rect.size.height/2);
+    CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius);
+    CGContextAddArcToPoint(context, rect.size.width - 2, 2, rect.size.width - 2, rect.size.height / 2, radius);
+    CGContextAddArcToPoint(context, rect.size.width - 2, rect.size.height - 2, rect.size.width - radius - 2, rect.size.height - 2, radius);
+    CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height/2, radius);
+    CGContextDrawPath(context, kCGPathFillStroke);
+    
+    CGContextSetFillColorWithColor(context, [_progressColor CGColor]);
+    radius = radius - 2;
+    CGFloat amount = self.progress * rect.size.width;
+    
+    // Progress in the middle area
+    if (amount >= radius + 4 && amount <= (rect.size.width - radius - 4)) {
+        CGContextMoveToPoint(context, 4, rect.size.height/2);
+        CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius);
+        CGContextAddLineToPoint(context, amount, 4);
+        CGContextAddLineToPoint(context, amount, radius + 4);
+        
+        CGContextMoveToPoint(context, 4, rect.size.height/2);
+        CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius);
+        CGContextAddLineToPoint(context, amount, rect.size.height - 4);
+        CGContextAddLineToPoint(context, amount, radius + 4);
+        
+        CGContextFillPath(context);
+    }
+    
+    // Progress in the right arc
+    else if (amount > radius + 4) {
+        CGFloat x = amount - (rect.size.width - radius - 4);
+
+        CGContextMoveToPoint(context, 4, rect.size.height/2);
+        CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius);
+        CGContextAddLineToPoint(context, rect.size.width - radius - 4, 4);
+        CGFloat angle = -acos(x/radius);
+        if (isnan(angle)) angle = 0;
+        CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height/2, radius, M_PI, angle, 0);
+        CGContextAddLineToPoint(context, amount, rect.size.height/2);
+
+        CGContextMoveToPoint(context, 4, rect.size.height/2);
+        CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius);
+        CGContextAddLineToPoint(context, rect.size.width - radius - 4, rect.size.height - 4);
+        angle = acos(x/radius);
+        if (isnan(angle)) angle = 0;
+        CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height/2, radius, -M_PI, angle, 1);
+        CGContextAddLineToPoint(context, amount, rect.size.height/2);
+        
+        CGContextFillPath(context);
+    }
+    
+    // Progress is in the left arc
+    else if (amount < radius + 4 && amount > 0) {
+        CGContextMoveToPoint(context, 4, rect.size.height/2);
+        CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius);
+        CGContextAddLineToPoint(context, radius + 4, rect.size.height/2);
+
+        CGContextMoveToPoint(context, 4, rect.size.height/2);
+        CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius);
+        CGContextAddLineToPoint(context, radius + 4, rect.size.height/2);
+        
+        CGContextFillPath(context);
+    }
+}
+
+@end
+
+
+@interface MBBackgroundView ()
+
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 || TARGET_OS_TV
+@property UIVisualEffectView *effectView;
+#endif
+#if !TARGET_OS_TV
+@property UIToolbar *toolbar;
+#endif
+
+@end
+
+
+@implementation MBBackgroundView
+
+#pragma mark - Lifecycle
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    if ((self = [super initWithFrame:frame])) {
+        if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_7_0) {
+            _style = MBProgressHUDBackgroundStyleBlur;
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 || TARGET_OS_TV
+            _blurEffectStyle = UIBlurEffectStyleLight;
+#endif
+            if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_8_0) {
+                _color = [UIColor colorWithWhite:0.8f alpha:0.6f];
+            } else {
+                _color = [UIColor colorWithWhite:0.95f alpha:0.6f];
+            }
+        } else {
+            _style = MBProgressHUDBackgroundStyleSolidColor;
+            _color = [[UIColor blackColor] colorWithAlphaComponent:0.8];
+        }
+
+        self.clipsToBounds = YES;
+
+        [self updateForBackgroundStyle];
+    }
+    return self;
+}
+
+#pragma mark - Layout
+
+- (CGSize)intrinsicContentSize {
+    // Smallest size possible. Content pushes against this.
+    return CGSizeZero;
+}
+
+#pragma mark - Appearance
+
+- (void)setStyle:(MBProgressHUDBackgroundStyle)style {
+    if (style == MBProgressHUDBackgroundStyleBlur && kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_7_0) {
+        style = MBProgressHUDBackgroundStyleSolidColor;
+    }
+    if (_style != style) {
+        _style = style;
+        [self updateForBackgroundStyle];
+    }
+}
+
+- (void)setColor:(UIColor *)color {
+    NSAssert(color, @"The color should not be nil.");
+    if (color != _color && ![color isEqual:_color]) {
+        _color = color;
+        [self updateViewsForColor:color];
+    }
+}
+
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 || TARGET_OS_TV
+
+- (void)setBlurEffectStyle:(UIBlurEffectStyle)blurEffectStyle {
+    if (_blurEffectStyle == blurEffectStyle) {
+        return;
+    }
+
+    _blurEffectStyle = blurEffectStyle;
+
+    [self updateForBackgroundStyle];
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Views
+
+- (void)updateForBackgroundStyle {
+    MBProgressHUDBackgroundStyle style = self.style;
+    if (style == MBProgressHUDBackgroundStyleBlur) {
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 || TARGET_OS_TV
+        if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_8_0) {
+            UIBlurEffect *effect = [UIBlurEffect effectWithStyle:self.blurEffectStyle];
+            UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect];
+            [self addSubview:effectView];
+            effectView.frame = self.bounds;
+            effectView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
+            self.backgroundColor = self.color;
+            self.layer.allowsGroupOpacity = NO;
+            self.effectView = effectView;
+        } else {
+#endif
+#if !TARGET_OS_TV
+            UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectInset(self.bounds, -100.f, -100.f)];
+            toolbar.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
+            toolbar.barTintColor = self.color;
+            toolbar.translucent = YES;
+            [self addSubview:toolbar];
+            self.toolbar = toolbar;
+#endif
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 || TARGET_OS_TV
+        }
+#endif
+    } else {
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 || TARGET_OS_TV
+        if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_8_0) {
+            [self.effectView removeFromSuperview];
+            self.effectView = nil;
+        } else {
+#endif
+#if !TARGET_OS_TV
+            [self.toolbar removeFromSuperview];
+            self.toolbar = nil;
+#endif
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 || TARGET_OS_TV
+        }
+#endif
+        self.backgroundColor = self.color;
+    }
+}
+
+- (void)updateViewsForColor:(UIColor *)color {
+    if (self.style == MBProgressHUDBackgroundStyleBlur) {
+        if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_8_0) {
+            self.backgroundColor = self.color;
+        } else {
+#if !TARGET_OS_TV
+            self.toolbar.barTintColor = color;
+#endif
+        }
+    } else {
+        self.backgroundColor = self.color;
+    }
+}
+
+@end
+
+
+@implementation MBProgressHUD (Deprecated)
+
+#pragma mark - Class
+
++ (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated {
+    NSArray *huds = [MBProgressHUD allHUDsForView:view];
+    for (MBProgressHUD *hud in huds) {
+        hud.removeFromSuperViewOnHide = YES;
+        [hud hideAnimated:animated];
+    }
+    return [huds count];
+}
+
++ (NSArray *)allHUDsForView:(UIView *)view {
+    NSMutableArray *huds = [NSMutableArray array];
+    NSArray *subviews = view.subviews;
+    for (UIView *aView in subviews) {
+        if ([aView isKindOfClass:self]) {
+            [huds addObject:aView];
+        }
+    }
+    return [NSArray arrayWithArray:huds];
+}
+
+#pragma mark - Lifecycle
+
+- (id)initWithWindow:(UIWindow *)window {
+    return [self initWithView:window];
+}
+
+#pragma mark - Show & hide
+
+- (void)show:(BOOL)animated {
+    [self showAnimated:animated];
+}
+
+- (void)hide:(BOOL)animated {
+    [self hideAnimated:animated];
+}
+
+- (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay {
+    [self hideAnimated:animated afterDelay:delay];
+}
+
+#pragma mark - Threading
+
+- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated {
+    [self showAnimated:animated whileExecutingBlock:^{
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+        // Start executing the requested task
+        [target performSelector:method withObject:object];
+#pragma clang diagnostic pop
+    }];
+}
+
+- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block {
+    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+    [self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:NULL];
+}
+
+- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(void (^)(void))completion {
+    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+    [self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:completion];
+}
+
+- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue {
+    [self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:NULL];
+}
+
+- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue completionBlock:(nullable MBProgressHUDCompletionBlock)completion {
+    self.taskInProgress = YES;
+    self.completionBlock = completion;
+    dispatch_async(queue, ^(void) {
+        block();
+        dispatch_async(dispatch_get_main_queue(), ^(void) {
+            [self cleanUp];
+        });
+    });
+    [self showAnimated:animated];
+}
+
+- (void)cleanUp {
+    self.taskInProgress = NO;
+    [self hideAnimated:self.useAnimation];
+}
+
+#pragma mark - Labels
+
+- (NSString *)labelText {
+    return self.label.text;
+}
+
+- (void)setLabelText:(NSString *)labelText {
+    MBMainThreadAssert();
+    self.label.text = labelText;
+}
+
+- (UIFont *)labelFont {
+    return self.label.font;
+}
+
+- (void)setLabelFont:(UIFont *)labelFont {
+    MBMainThreadAssert();
+    self.label.font = labelFont;
+}
+
+- (UIColor *)labelColor {
+    return self.label.textColor;
+}
+
+- (void)setLabelColor:(UIColor *)labelColor {
+    MBMainThreadAssert();
+    self.label.textColor = labelColor;
+}
+
+- (NSString *)detailsLabelText {
+    return self.detailsLabel.text;
+}
+
+- (void)setDetailsLabelText:(NSString *)detailsLabelText {
+    MBMainThreadAssert();
+    self.detailsLabel.text = detailsLabelText;
+}
+
+- (UIFont *)detailsLabelFont {
+    return self.detailsLabel.font;
+}
+
+- (void)setDetailsLabelFont:(UIFont *)detailsLabelFont {
+    MBMainThreadAssert();
+    self.detailsLabel.font = detailsLabelFont;
+}
+
+- (UIColor *)detailsLabelColor {
+    return self.detailsLabel.textColor;
+}
+
+- (void)setDetailsLabelColor:(UIColor *)detailsLabelColor {
+    MBMainThreadAssert();
+    self.detailsLabel.textColor = detailsLabelColor;
+}
+
+- (CGFloat)opacity {
+    return _opacity;
+}
+
+- (void)setOpacity:(CGFloat)opacity {
+    MBMainThreadAssert();
+    _opacity = opacity;
+}
+
+- (UIColor *)color {
+    return self.bezelView.color;
+}
+
+- (void)setColor:(UIColor *)color {
+    MBMainThreadAssert();
+    self.bezelView.color = color;
+}
+
+- (CGFloat)yOffset {
+    return self.offset.y;
+}
+
+- (void)setYOffset:(CGFloat)yOffset {
+    MBMainThreadAssert();
+    self.offset = CGPointMake(self.offset.x, yOffset);
+}
+
+- (CGFloat)xOffset {
+    return self.offset.x;
+}
+
+- (void)setXOffset:(CGFloat)xOffset {
+    MBMainThreadAssert();
+    self.offset = CGPointMake(xOffset, self.offset.y);
+}
+
+- (CGFloat)cornerRadius {
+    return self.bezelView.layer.cornerRadius;
+}
+
+- (void)setCornerRadius:(CGFloat)cornerRadius {
+    MBMainThreadAssert();
+    self.bezelView.layer.cornerRadius = cornerRadius;
+}
+
+- (BOOL)dimBackground {
+    MBBackgroundView *backgroundView = self.backgroundView;
+    UIColor *dimmedColor =  [UIColor colorWithWhite:0.f alpha:.2f];
+    return backgroundView.style == MBProgressHUDBackgroundStyleSolidColor && [backgroundView.color isEqual:dimmedColor];
+}
+
+- (void)setDimBackground:(BOOL)dimBackground {
+    MBMainThreadAssert();
+    self.backgroundView.style = MBProgressHUDBackgroundStyleSolidColor;
+    self.backgroundView.color = dimBackground ? [UIColor colorWithWhite:0.f alpha:.2f] : [UIColor clearColor];
+}
+
+- (CGSize)size {
+    return self.bezelView.frame.size;
+}
+
+- (UIColor *)activityIndicatorColor {
+    return _activityIndicatorColor;
+}
+
+- (void)setActivityIndicatorColor:(UIColor *)activityIndicatorColor {
+    if (activityIndicatorColor != _activityIndicatorColor) {
+        _activityIndicatorColor = activityIndicatorColor;
+        UIActivityIndicatorView *indicator = (UIActivityIndicatorView *)self.indicator;
+        if ([indicator isKindOfClass:[UIActivityIndicatorView class]]) {
+            [indicator setColor:activityIndicatorColor];
+        }
+    }
+}
+
+@end
+
+@implementation MBProgressHUDRoundedButton
+
+#pragma mark - Lifecycle
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        CALayer *layer = self.layer;
+        layer.borderWidth = 1.f;
+    }
+    return self;
+}
+
+#pragma mark - Layout
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    // Fully rounded corners
+    CGFloat height = CGRectGetHeight(self.bounds);
+    self.layer.cornerRadius = ceil(height / 2.f);
+}
+
+- (CGSize)intrinsicContentSize {
+    // Only show if we have associated control events
+    if (self.allControlEvents == 0) return CGSizeZero;
+    CGSize size = [super intrinsicContentSize];
+    // Add some side padding
+    size.width += 20.f;
+    return size;
+}
+
+#pragma mark - Color
+
+- (void)setTitleColor:(UIColor *)color forState:(UIControlState)state {
+    [super setTitleColor:color forState:state];
+    // Update related colors
+    [self setHighlighted:self.highlighted];
+    self.layer.borderColor = color.CGColor;
+}
+
+- (void)setHighlighted:(BOOL)highlighted {
+    [super setHighlighted:highlighted];
+    UIColor *baseColor = [self titleColorForState:UIControlStateSelected];
+    self.backgroundColor = highlighted ? [baseColor colorWithAlphaComponent:0.1f] : [UIColor clearColor];
+}
+
+@end