787 lines
24 KiB
Objective-C
Executable File
787 lines
24 KiB
Objective-C
Executable File
//
|
|
// MMProgressHUD.m
|
|
// MMProgressHUD
|
|
//
|
|
// Created by Lars Anderson on 10/7/11.
|
|
// Copyright 2011 Mutual Mobile. All rights reserved.
|
|
//
|
|
|
|
#import <QuartzCore/QuartzCore.h>
|
|
|
|
#import "MMProgressHUD.h"
|
|
#import "MMProgressHUDCommon.h"
|
|
#import "MMProgressHUD+Animations.h"
|
|
|
|
#import "MMProgressHUDWindow.h"
|
|
#import "MMProgressHUDViewController.h"
|
|
|
|
#import "MMProgressHUDOverlayView.h"
|
|
#import "MMVectorImage.h"
|
|
|
|
#import "MMLinearProgressView.h"
|
|
#import "MMRadialProgressView.h"
|
|
|
|
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0
|
|
#error MMProgressHUD uses APIs only available in iOS 5.0+
|
|
#endif
|
|
|
|
NSString * const MMProgressHUDDefaultConfirmationMessage = @"Cancel?";
|
|
NSString * const MMProgressHUDAnimationShow = @"mm-progress-hud-present-animation";
|
|
NSString * const MMProgressHUDAnimationDismiss = @"mm-progress-hud-dismiss-animation";
|
|
NSString * const MMProgressHUDAnimationWindowFadeOut = @"mm-progress-hud-window-fade-out";
|
|
NSString * const MMProgressHUDAnimationKeyShowAnimation = @"show";
|
|
NSString * const MMProgressHUDAnimationKeyDismissAnimation = @"dismiss";
|
|
|
|
NSUInteger const MMProgressHUDConfirmationPulseCount = 8;//Keep this number even
|
|
|
|
CGFloat const MMProgressHUDStandardDismissDelay = 0.75f;
|
|
|
|
CGSize const MMProgressHUDDefaultImageSize = {37.f, 37.f};
|
|
|
|
#pragma mark - MMProgressHUD
|
|
@interface MMProgressHUD () <MMHudDelegate>
|
|
|
|
@property (nonatomic, strong) MMProgressHUDWindow *window;
|
|
@property (nonatomic, readwrite, getter = isVisible) BOOL visible;
|
|
@property (nonatomic, copy) NSString *title;
|
|
@property (nonatomic, copy) NSString *status;
|
|
@property (nonatomic, strong) UIImage *image;
|
|
@property (nonatomic, copy) NSArray *animationImages;
|
|
@property (nonatomic, strong) CAAnimation *queuedShowAnimation;
|
|
@property (nonatomic, strong) CAAnimation *queuedDismissAnimation;
|
|
@property (nonatomic, readwrite, strong) MMProgressHUDOverlayView *overlayView;
|
|
@property (nonatomic, strong) NSTimer *dismissDelayTimer;
|
|
@property (nonatomic, copy) NSString *tempStatus;
|
|
@property (nonatomic, strong) NSTimer *confirmationTimer;
|
|
@property (nonatomic, getter = isConfirmed) BOOL confirmed;
|
|
@property (nonatomic, assign) BOOL presentedAnimated;
|
|
@property (nonatomic, strong) MMProgressHUDViewController *presentationViewController;
|
|
|
|
@end
|
|
|
|
@implementation MMProgressHUD
|
|
|
|
#pragma mark - Class Methods
|
|
+ (instancetype)sharedHUD {
|
|
static MMProgressHUD *__sharedHUD = nil;
|
|
|
|
static dispatch_once_t mmSharedHUDOnceToken;
|
|
dispatch_once(&mmSharedHUDOnceToken, ^{
|
|
__sharedHUD = [[MMProgressHUD alloc] init];
|
|
});
|
|
|
|
return __sharedHUD;
|
|
}
|
|
|
|
#pragma mark - Instance Presentation Methods
|
|
- (void)showDeterminateProgressWithTitle:(NSString *)title
|
|
status:(NSString *)status
|
|
confirmationMessage:(NSString *)confirmation
|
|
cancelBlock:(void (^)(void))cancelBlock
|
|
images:(NSArray *)images {
|
|
[self.hud setIndeterminate:NO];
|
|
|
|
[self showWithTitle:title
|
|
status:status
|
|
confirmationMessage:confirmation
|
|
cancelBlock:cancelBlock
|
|
images:images];
|
|
}
|
|
|
|
- (void)showWithTitle:(NSString *)title
|
|
status:(NSString *)status
|
|
confirmationMessage:(NSString *)confirmationMessage
|
|
cancelBlock:(void(^)(void))cancelBlock
|
|
images:(NSArray *)images {
|
|
|
|
self.image = nil;
|
|
self.animationImages = nil;
|
|
|
|
if (images.count == 1) {
|
|
self.image = images[0];
|
|
}
|
|
else if (images.count > 0) {
|
|
self.animationImages = images;
|
|
}
|
|
else if (self.spinAnimationImages.count == 1) {
|
|
self.image = self.spinAnimationImages[0];
|
|
}
|
|
else if (self.spinAnimationImages.count > 0) {
|
|
self.animationImages = self.spinAnimationImages;
|
|
}
|
|
|
|
self.cancelBlock = cancelBlock;
|
|
self.title = title;
|
|
self.status = status;
|
|
|
|
if (confirmationMessage.length > 0) {
|
|
self.confirmationMessage = confirmationMessage;
|
|
}
|
|
else {
|
|
self.confirmationMessage = MMProgressHUDDefaultConfirmationMessage;
|
|
}
|
|
|
|
if ((self.isVisible == YES) &&
|
|
(self.window != nil) &&
|
|
([self.hud.layer animationForKey:MMProgressHUDAnimationKeyDismissAnimation] == nil)) {
|
|
[self _updateHUDAnimated:YES withCompletion:nil];
|
|
}
|
|
else {
|
|
[self show];
|
|
}
|
|
}
|
|
|
|
- (void)dismissWithCompletionState:(MMProgressHUDCompletionState)completionState
|
|
title:(NSString *)title
|
|
status:(NSString *)status
|
|
afterDelay:(NSTimeInterval)delay {
|
|
if (title) {
|
|
self.title = title;
|
|
}
|
|
|
|
if (status) {
|
|
self.status = status;
|
|
}
|
|
|
|
self.hud.completionState = completionState;
|
|
|
|
if (self.isVisible) {
|
|
[self _updateHUDAnimated:YES withCompletion:^(BOOL completed) {
|
|
[self dismissAfterDelay:delay];
|
|
}];
|
|
}
|
|
}
|
|
|
|
- (void)updateProgress:(CGFloat)progress withStatus:(NSString *)status title:(NSString *)title{
|
|
[self setProgress:progress];
|
|
|
|
if (status != nil) {
|
|
self.hud.messageText = status;
|
|
}
|
|
|
|
if (title != nil) {
|
|
self.hud.titleText = title;
|
|
}
|
|
|
|
if (self.isVisible &&
|
|
(self.window != nil)) {
|
|
|
|
void(^animationCompletion)(BOOL completed) = ^(BOOL completed) {
|
|
if (progress >= 1.f &&
|
|
self.progressCompletion != nil) {
|
|
double delayInSeconds = 0.33f;//allow enough time for progress to animate
|
|
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
|
|
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
|
|
if (self.progressCompletion) {
|
|
self.progressCompletion();
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
[self _updateHUDAnimated:YES
|
|
withCompletion:animationCompletion];
|
|
}
|
|
else {
|
|
[self show];
|
|
}
|
|
}
|
|
|
|
#pragma mark - Initializers
|
|
- (instancetype)init {
|
|
if ( (self = [super initWithFrame:CGRectZero]) ) {
|
|
self.hud = [[MMHud alloc] init];
|
|
self.hud.delegate = self;
|
|
|
|
UIColor *imageFill = [UIColor colorWithWhite:1.f alpha:1.f];
|
|
self.errorImage = [MMVectorImage
|
|
vectorImageShapeOfType:MMVectorShapeTypeX
|
|
size:MMProgressHUDDefaultImageSize
|
|
fillColor:imageFill];
|
|
self.successImage = [MMVectorImage
|
|
vectorImageShapeOfType:MMVectorShapeTypeCheck
|
|
size:MMProgressHUDDefaultImageSize
|
|
fillColor:imageFill];
|
|
|
|
[self setAutoresizingMask:
|
|
UIViewAutoresizingFlexibleHeight |
|
|
UIViewAutoresizingFlexibleWidth];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc {
|
|
MMHudLog(@"dealloc");
|
|
|
|
if (_window != nil) {
|
|
[_window setHidden:YES];
|
|
}
|
|
}
|
|
|
|
- (void)forceCleanup {
|
|
//Do not invoke this method unless you are in a unit test environment
|
|
if (self.window != nil) {
|
|
[self.window setHidden:YES];
|
|
}
|
|
self.presentationViewController = nil;
|
|
self.window.rootViewController = nil;
|
|
self.window = nil;
|
|
}
|
|
|
|
#pragma mark - Passthrough Properties
|
|
- (void)setOverlayMode:(MMProgressHUDWindowOverlayMode)overlayMode {
|
|
self.overlayView.overlayMode = overlayMode;
|
|
}
|
|
|
|
- (MMProgressHUDWindowOverlayMode)overlayMode {
|
|
return self.overlayView.overlayMode;
|
|
}
|
|
|
|
- (void)setAnimationLoopDuration:(CGFloat)animationLoopDuration {
|
|
self.hud.animationLoopDuration = animationLoopDuration;
|
|
}
|
|
|
|
- (CGFloat)animationLoopDuration {
|
|
return self.hud.animationLoopDuration;
|
|
}
|
|
|
|
- (void)setProgress:(CGFloat)progress {
|
|
[self.hud setProgress:progress animated:YES];
|
|
|
|
self.hud.accessibilityValue = [NSString stringWithFormat:@"%i%%", (int)(progress/1.f*100)];
|
|
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, [NSString stringWithFormat:@"%@ %@", self.hud.accessibilityLabel, self.hud.accessibilityValue]);
|
|
}
|
|
|
|
- (CGFloat)progress {
|
|
return self.hud.progress;
|
|
}
|
|
|
|
- (void)setProgressStyle:(MMProgressHUDProgressStyle)progressStyle{
|
|
self.hud.progressStyle = progressStyle;
|
|
|
|
switch (progressStyle) {
|
|
case MMProgressHUDProgressStyleIndeterminate:
|
|
self.hud.progressViewClass = nil;
|
|
self.accessibilityTraits &= ~UIAccessibilityTraitUpdatesFrequently;
|
|
break;
|
|
case MMProgressHUDProgressStyleLinear:
|
|
self.hud.progressViewClass = [MMLinearProgressView class];
|
|
self.accessibilityTraits |= UIAccessibilityTraitUpdatesFrequently;
|
|
break;
|
|
case MMProgressHUDProgressStyleRadial:
|
|
self.hud.progressViewClass = [MMRadialProgressView class];
|
|
self.accessibilityTraits |= UIAccessibilityTraitUpdatesFrequently;
|
|
break;
|
|
}
|
|
}
|
|
|
|
- (MMProgressHUDProgressStyle)progressStyle{
|
|
return self.hud.progressStyle;
|
|
}
|
|
|
|
- (void)setTitle:(NSString *)title {
|
|
self.hud.titleText = title;
|
|
}
|
|
|
|
- (NSString *)title {
|
|
return self.hud.titleText;
|
|
}
|
|
|
|
- (void)setStatus:(NSString *)status {
|
|
self.hud.messageText = status;
|
|
}
|
|
|
|
- (NSString *)status {
|
|
return self.hud.messageText;
|
|
}
|
|
|
|
- (void)setImage:(UIImage *)image{
|
|
_image = image;
|
|
[self.hud setImage:image];
|
|
}
|
|
|
|
#pragma mark - Property Overrides
|
|
|
|
- (void)setProgressViewClass:(Class)progressViewClass{
|
|
self.hud.progressViewClass = progressViewClass;
|
|
}
|
|
|
|
- (Class)progressViewClass{
|
|
return self.hud.progressViewClass;
|
|
}
|
|
|
|
- (MMProgressHUDOverlayView *)overlayView {
|
|
if (_overlayView == nil) {
|
|
_overlayView = [[MMProgressHUDOverlayView alloc] init];
|
|
_overlayView.alpha = 0.f;
|
|
_overlayView.autoresizingMask = (UIViewAutoresizingFlexibleHeight |
|
|
UIViewAutoresizingFlexibleWidth);
|
|
}
|
|
|
|
return _overlayView;
|
|
}
|
|
|
|
- (CGColorRef)glowColor {
|
|
if (_glowColor == NULL) {
|
|
CGColorRef redColor = CGColorRetain([UIColor redColor].CGColor);
|
|
self.glowColor = redColor;
|
|
CGColorRelease(redColor);
|
|
}
|
|
|
|
return _glowColor;
|
|
}
|
|
|
|
- (MMHud *)hud {
|
|
if (_hud == nil) {
|
|
_hud = [[MMHud alloc] init];
|
|
}
|
|
|
|
return _hud;
|
|
}
|
|
|
|
- (void)setProgressCompletion:(void (^)(void))progressCompletion {
|
|
if (progressCompletion != nil) {
|
|
__typeof(self) __weak weakSelf = self;
|
|
_progressCompletion = ^(void) {
|
|
progressCompletion();
|
|
|
|
weakSelf.progressCompletion = nil;
|
|
};
|
|
}
|
|
else {
|
|
_progressCompletion = nil;
|
|
}
|
|
}
|
|
|
|
- (void)setCancelBlock:(void (^)(void))cancelBlock {
|
|
_cancelBlock = cancelBlock;
|
|
|
|
if (cancelBlock != nil) {
|
|
self.hud.accessibilityTraits |=
|
|
(UIAccessibilityTraitAllowsDirectInteraction |
|
|
UIAccessibilityTraitButton);
|
|
}
|
|
else {
|
|
self.hud.accessibilityTraits &= ~(UIAccessibilityTraitAllowsDirectInteraction |
|
|
UIAccessibilityTraitButton);
|
|
}
|
|
}
|
|
|
|
#pragma mark - Builders
|
|
- (void)_buildHUDWindow {
|
|
if (self.window == nil) {
|
|
self.window = [[MMProgressHUDWindow alloc] init];
|
|
|
|
if (self.presentationViewController == nil) {
|
|
self.presentationViewController = [[MMProgressHUDViewController alloc] init];
|
|
if (self.presentationViewController.view != self)
|
|
[self.presentationViewController setView:self];
|
|
}
|
|
|
|
[self.window setRootViewController:self.presentationViewController];
|
|
|
|
[self _buildOverlayViewForMode:self.overlayMode inView:self.window];
|
|
[self.window setHidden:NO];
|
|
}
|
|
}
|
|
|
|
- (void)_buildOverlayViewForMode:(MMProgressHUDWindowOverlayMode)overlayMode inView:(UIView *)view {
|
|
|
|
self.overlayView.frame = view.bounds;
|
|
self.overlayView.overlayMode = overlayMode;
|
|
|
|
[view insertSubview:self.overlayView atIndex:0];
|
|
}
|
|
|
|
- (void)_buildHUD {
|
|
[self setAutoresizingMask:
|
|
UIViewAutoresizingFlexibleHeight |
|
|
UIViewAutoresizingFlexibleWidth];
|
|
|
|
[self _buildHUDWindow];
|
|
|
|
UITapGestureRecognizer *tapToDismiss = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_handleTap:)];
|
|
[tapToDismiss setNumberOfTapsRequired:1];
|
|
[tapToDismiss setNumberOfTouchesRequired:1];
|
|
[self addGestureRecognizer:tapToDismiss];
|
|
|
|
self.hud.image = self.image;
|
|
self.hud.animationImages = self.animationImages;
|
|
|
|
self.hud.layer.transform = CATransform3DIdentity;
|
|
|
|
[self.hud setNeedsUpdate:YES];
|
|
|
|
[self.hud applyLayoutFrames];
|
|
|
|
[self addSubview:self.hud];
|
|
}
|
|
|
|
#pragma mark - Layout
|
|
- (void)_updateMessageLabelsAnimated:(BOOL)animated {
|
|
[self.hud updateTitle:self.title message:self.status animated:animated];
|
|
}
|
|
|
|
- (void)_updateHUDAnimated:(BOOL)animated withCompletion:(void(^)(BOOL completed))completionBlock {
|
|
MMHudLog(@"Updating %@ with completion...", NSStringFromClass(self.class));
|
|
|
|
[self killDismissDelayTimer];
|
|
|
|
if (animated) {
|
|
[UIView
|
|
animateWithDuration:0.1f
|
|
delay:0.f
|
|
options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState
|
|
animations:^{
|
|
[self _updateHUD];
|
|
}
|
|
completion:completionBlock];
|
|
}
|
|
else {
|
|
[self _updateHUD];
|
|
|
|
if (completionBlock != nil) {
|
|
completionBlock(YES);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)_updateHUD {
|
|
[self.hud updateLayoutFrames];
|
|
|
|
[self.hud updateAnimated:YES withCompletion:nil];
|
|
|
|
self.hud.center = [self _windowCenterForHUDAnchor:self.hud.layer.anchorPoint];
|
|
}
|
|
|
|
- (void)killDismissDelayTimer {
|
|
if ([self.dismissDelayTimer isValid]) {
|
|
[self.dismissDelayTimer invalidate];
|
|
}
|
|
|
|
self.dismissDelayTimer = nil;
|
|
}
|
|
|
|
- (CGPoint)_windowCenterForHUDAnchor:(CGPoint)anchor {
|
|
|
|
CGFloat hudHeight = CGRectGetHeight(self.hud.frame);
|
|
|
|
CGPoint windowCenter = self.window.center;
|
|
CGFloat x = roundf(windowCenter.x);
|
|
CGFloat y = roundf(windowCenter.y + (anchor.y - 0.5f) * hudHeight);
|
|
UIInterfaceOrientation currentOrientation = [[self.window rootViewController] interfaceOrientation];
|
|
NSString *reqSysVer = @"8.0";
|
|
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
|
|
BOOL usesWindowTransformRotation = ([currSysVer compare:reqSysVer
|
|
options:NSNumericSearch] != NSOrderedAscending);
|
|
|
|
if (usesWindowTransformRotation == NO) {
|
|
if (UIInterfaceOrientationIsPortrait(currentOrientation)) {
|
|
|
|
y = roundf(windowCenter.y + (anchor.y - 0.5f) * hudHeight);
|
|
x = roundf(windowCenter.x);
|
|
}
|
|
else {
|
|
x = roundf(windowCenter.y);
|
|
y = roundf(windowCenter.x + (anchor.y - 0.5f) * hudHeight);
|
|
}
|
|
}
|
|
|
|
CGPoint position = CGPointMake(x, y);
|
|
|
|
return [self _antialiasedPositionPointForPoint:position forLayer:self.hud.layer];
|
|
}
|
|
|
|
#pragma mark - Presentation
|
|
- (void)show {
|
|
[self killDismissDelayTimer];
|
|
|
|
NSAssert([NSThread isMainThread], @"Show should be run on main thread!");
|
|
|
|
[CATransaction begin];
|
|
[CATransaction setDisableActions:YES];
|
|
|
|
[self _buildHUD];
|
|
|
|
self.presentedAnimated = YES;
|
|
switch (self.presentationStyle) {
|
|
case MMProgressHUDPresentationStyleDrop:
|
|
[self _showWithDropAnimation];
|
|
break;
|
|
case MMProgressHUDPresentationStyleExpand:
|
|
[self _showWithExpandAnimation];
|
|
break;
|
|
case MMProgressHUDPresentationStyleShrink:
|
|
[self _showWithShrinkAnimation];
|
|
break;
|
|
case MMProgressHUDPresentationStyleSwingLeft:
|
|
[self _showWithSwingInAnimationFromLeft:YES];
|
|
break;
|
|
case MMProgressHUDPresentationStyleSwingRight:
|
|
[self _showWithSwingInAnimationFromLeft:NO];
|
|
break;
|
|
case MMProgressHUDPresentationStyleBalloon:
|
|
[self _showWithBalloonAnimation];
|
|
break;
|
|
case MMProgressHUDPresentationStyleFade:
|
|
[self _showWithFadeAnimation];
|
|
break;
|
|
case MMProgressHUDPresentationStyleNone:
|
|
default:{
|
|
self.presentedAnimated = NO;
|
|
|
|
CGPoint newCenter = [self _windowCenterForHUDAnchor:self.hud.layer.anchorPoint];
|
|
|
|
self.hud.center = newCenter;
|
|
self.hud.layer.transform = CATransform3DIdentity;
|
|
self.hud.alpha = 1.f;
|
|
self.overlayView.alpha = 1.0f;
|
|
self.visible = YES;
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
[CATransaction commit];
|
|
|
|
CGFloat duration = (self.presentationStyle == MMProgressHUDPresentationStyleNone) ? 0.f : MMProgressHUDAnimateInDurationShort;
|
|
|
|
[UIView
|
|
animateWithDuration:duration
|
|
delay:0.f
|
|
options:UIViewAnimationOptionCurveEaseOut |
|
|
UIViewAnimationOptionBeginFromCurrentState
|
|
animations:^{
|
|
self.overlayView.alpha = 1.0f;
|
|
}
|
|
completion:^(BOOL completed) {
|
|
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self.hud.accessibilityLabel);
|
|
}];
|
|
}
|
|
|
|
- (void)dismissAfterDelay:(NSTimeInterval)delay {
|
|
if (self.visible == NO) {
|
|
MMHudLog(@"Preventing delayed dismissal when already dismissed!");
|
|
return;
|
|
}
|
|
|
|
[self killDismissDelayTimer];
|
|
|
|
self.dismissDelayTimer = [NSTimer scheduledTimerWithTimeInterval:delay target:self selector:@selector(dismiss) userInfo:nil repeats:NO];
|
|
}
|
|
|
|
- (void)dismiss {
|
|
if (self.visible == NO) {
|
|
MMHudLog(@"Preventing dismissal when already dismissed!");
|
|
return;
|
|
}
|
|
NSAssert([NSThread isMainThread], @"Dismiss method should be run on main thread!");
|
|
|
|
MMHudLog(@"Dismissing...");
|
|
|
|
switch (self.presentationStyle) {
|
|
case MMProgressHUDPresentationStyleDrop:
|
|
[self _dismissWithDropAnimation];
|
|
break;
|
|
case MMProgressHUDPresentationStyleExpand:
|
|
[self _dismissWithExpandAnimation];
|
|
break;
|
|
case MMProgressHUDPresentationStyleShrink:
|
|
[self _dismissWithShrinkAnimation];
|
|
break;
|
|
case MMProgressHUDPresentationStyleSwingLeft:
|
|
[self _dismissWithSwingLeftAnimation];
|
|
break;
|
|
case MMProgressHUDPresentationStyleSwingRight:
|
|
[self _dismissWithSwingRightAnimation];
|
|
break;
|
|
case MMProgressHUDPresentationStyleBalloon:
|
|
[self _dismissWithBalloonAnimation];
|
|
break;
|
|
case MMProgressHUDPresentationStyleFade:
|
|
[self _dismissWithFadeAnimation];
|
|
break;
|
|
case MMProgressHUDPresentationStyleNone:
|
|
default:
|
|
self.hud.layer.opacity = 0.f;
|
|
self.overlayView.layer.opacity = 0.f;
|
|
|
|
[self removeFromSuperview];
|
|
|
|
self.visible = NO;
|
|
[self.window setHidden:YES];
|
|
self.window = nil;
|
|
break;
|
|
}
|
|
|
|
typeof(self) __weak weakSelf = self;
|
|
if (!self.queuedDismissAnimation) {
|
|
[self _fadeOutAndCleanUp];
|
|
} else {
|
|
void (^oldCompletion)(void) = [self.showAnimationCompletion copy];
|
|
self.showAnimationCompletion = ^{
|
|
[weakSelf _fadeOutAndCleanUp];
|
|
if (oldCompletion)
|
|
oldCompletion();
|
|
};
|
|
}
|
|
}
|
|
|
|
- (void)_fadeOutAndCleanUp
|
|
{
|
|
NSTimeInterval duration = (self.presentationStyle == MMProgressHUDPresentationStyleNone) ? 0.0 : MMProgressHUDAnimateOutDurationLong;
|
|
NSTimeInterval delay = (self.presentationStyle == MMProgressHUDPresentationStyleDrop) ? MMProgressHUDAnimateOutDurationShort : 0.0;
|
|
|
|
[UIView
|
|
animateWithDuration:duration
|
|
delay:delay
|
|
options:UIViewAnimationOptionCurveEaseIn |
|
|
UIViewAnimationOptionBeginFromCurrentState
|
|
animations:^{
|
|
self.overlayView.alpha = 0.f;
|
|
}
|
|
completion:^(BOOL finished) {
|
|
|
|
self.image = nil;
|
|
self.animationImages = nil;
|
|
self.progress = 0.f;
|
|
self.hud.completionState = MMProgressHUDCompletionStateNone;
|
|
[self.presentationViewController removeFromParentViewController];
|
|
[self removeFromSuperview];
|
|
self.presentationViewController.view = nil;
|
|
self.presentationViewController = nil;
|
|
|
|
[self.window setHidden:YES], self.window = nil;
|
|
|
|
self.cancelled = NO;
|
|
|
|
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
|
|
}];
|
|
}
|
|
|
|
- (CGPoint)_antialiasedPositionPointForPoint:(CGPoint)oldCenter forLayer:(CALayer *)layer {
|
|
CGPoint newCenter = oldCenter;
|
|
|
|
CGSize viewSize = layer.bounds.size;
|
|
CGPoint anchor = layer.anchorPoint;
|
|
|
|
double intPart;
|
|
CGFloat viewXRemainder = modf(viewSize.width/2,&intPart);
|
|
CGFloat viewCenterXRemainder = modf(oldCenter.x/2, &intPart);
|
|
|
|
if (anchor.x != 0.f && anchor.x != 1.f) {
|
|
if (((viewXRemainder == 0) &&//if view width is even
|
|
(viewCenterXRemainder != 0)) ||//and if center x is odd
|
|
((viewXRemainder != 0) &&//if view width is odd
|
|
(viewCenterXRemainder == 0))) {//and if center x is even
|
|
newCenter.x = oldCenter.x + viewXRemainder;
|
|
}
|
|
}
|
|
|
|
CGFloat viewYRemainder = modf(viewSize.height/2,&intPart);
|
|
CGFloat viewCenterYRemainder = modf(oldCenter.y/2, &intPart);
|
|
|
|
if (anchor.y != 0.f && anchor.y != 1.f) {
|
|
if (((viewYRemainder == 0) &&//if view width is even
|
|
(viewCenterYRemainder != 0)) ||//and if center x is odd
|
|
((viewYRemainder != 0) &&//if view width is odd
|
|
(viewCenterYRemainder == 0))) {//and if center x is even
|
|
newCenter.y = oldCenter.y + viewYRemainder;
|
|
}
|
|
}
|
|
|
|
return newCenter;
|
|
}
|
|
|
|
#pragma mark - Gestures
|
|
- (void)_handleTap:(UITapGestureRecognizer *)recognizer {
|
|
MMHudLog(@"Handling tap");
|
|
|
|
if ((self.cancelBlock != nil) &&
|
|
(self.confirmed == NO)) {
|
|
MMHudLog(@"Asking to confirm cancel");
|
|
|
|
self.confirmed = YES;
|
|
|
|
self.tempStatus = [self.status copy];
|
|
CGFloat timerDuration = MMProgressHUDAnimateInDurationNormal*MMProgressHUDConfirmationPulseCount;
|
|
self.confirmationTimer = [NSTimer scheduledTimerWithTimeInterval:timerDuration
|
|
target:self
|
|
selector:@selector(_resetConfirmationTimer:)
|
|
userInfo:nil
|
|
repeats:NO];
|
|
|
|
self.status = self.confirmationMessage;
|
|
|
|
[self.hud updateTitle:self.hud.titleText message:self.confirmationMessage animated:YES];
|
|
|
|
|
|
|
|
[self _beginGlowAnimation];
|
|
}
|
|
else if (self.confirmed) {
|
|
self.cancelled = YES;
|
|
MMHudLog(@"confirmed to dismiss!");
|
|
|
|
[self.confirmationTimer invalidate], self.confirmationTimer = nil;
|
|
|
|
if (self.cancelBlock != nil) {
|
|
self.cancelBlock();
|
|
}
|
|
|
|
self.hud.completionState = MMProgressHUDCompletionStateError;
|
|
[self.hud setNeedsUpdate:YES];
|
|
[self.hud updateAnimated:YES
|
|
withCompletion:^(__unused BOOL completed) {
|
|
[self dismiss];
|
|
}];
|
|
|
|
self.confirmed = NO;
|
|
}
|
|
}
|
|
|
|
- (void)_resetConfirmationTimer:(NSTimer *)timer {
|
|
MMHudLog(@"Resetting confirmation timer");
|
|
|
|
[self.confirmationTimer invalidate], self.confirmationTimer = nil;
|
|
self.status = self.tempStatus;
|
|
self.tempStatus = nil;
|
|
|
|
self.confirmed = NO;
|
|
|
|
[self _endGlowAnimation];
|
|
|
|
[self.hud updateTitle:self.hud.titleText message:self.status animated:YES];
|
|
}
|
|
|
|
- (UIImage *)_imageForCompletionState:(MMProgressHUDCompletionState)completionState {
|
|
switch (completionState) {
|
|
case MMProgressHUDCompletionStateError:
|
|
return self.errorImage;
|
|
case MMProgressHUDCompletionStateSuccess:
|
|
return self.successImage;
|
|
case MMProgressHUDCompletionStateNone:
|
|
return nil;
|
|
}
|
|
}
|
|
|
|
#pragma mark - MMHud Delegate
|
|
- (void)hudDidCompleteProgress:(MMHud *)hud {
|
|
if (self.progressCompletion != nil) {
|
|
self.progressCompletion();
|
|
}
|
|
|
|
self.hud.accessibilityValue = nil;
|
|
}
|
|
|
|
- (UIImage *)hud:(MMHud *)hud imageForCompletionState:(MMProgressHUDCompletionState)completionState {
|
|
return [self _imageForCompletionState:completionState];
|
|
}
|
|
|
|
- (CGPoint)hudCenterPointForDisplay:(MMHud *)hud {
|
|
return [self _windowCenterForHUDAnchor:hud.layer.anchorPoint];
|
|
}
|
|
|
|
@end
|