project list bug fixed, add hud
This commit is contained in:
parent
863bfa7564
commit
ae4b8d4f08
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2013 Matej Bukovinski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,484 @@
|
|||
//
|
||||
// MBProgressHUD.h
|
||||
// Version 0.7
|
||||
// Created by Matej Bukovinski on 2.4.09.
|
||||
//
|
||||
|
||||
// This code is distributed under the terms and conditions of the MIT license.
|
||||
|
||||
// Copyright (c) 2013 Matej Bukovinski
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
@protocol MBProgressHUDDelegate;
|
||||
|
||||
|
||||
typedef enum {
|
||||
/** Progress is shown using an UIActivityIndicatorView. This is the default. */
|
||||
MBProgressHUDModeIndeterminate,
|
||||
/** Progress is shown using a round, pie-chart like, progress view. */
|
||||
MBProgressHUDModeDeterminate,
|
||||
/** Progress is shown using a horizontal progress bar */
|
||||
MBProgressHUDModeDeterminateHorizontalBar,
|
||||
/** Progress is shown using a ring-shaped progress view. */
|
||||
MBProgressHUDModeAnnularDeterminate,
|
||||
/** Shows a custom view */
|
||||
MBProgressHUDModeCustomView,
|
||||
/** Shows only labels */
|
||||
MBProgressHUDModeText
|
||||
} MBProgressHUDMode;
|
||||
|
||||
typedef enum {
|
||||
/** Opacity animation */
|
||||
MBProgressHUDAnimationFade,
|
||||
/** Opacity + scale animation */
|
||||
MBProgressHUDAnimationZoom,
|
||||
MBProgressHUDAnimationZoomOut = MBProgressHUDAnimationZoom,
|
||||
MBProgressHUDAnimationZoomIn
|
||||
} MBProgressHUDAnimation;
|
||||
|
||||
|
||||
#ifndef MB_INSTANCETYPE
|
||||
#if __has_feature(objc_instancetype)
|
||||
#define MB_INSTANCETYPE instancetype
|
||||
#else
|
||||
#define MB_INSTANCETYPE id
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MB_STRONG
|
||||
#if __has_feature(objc_arc)
|
||||
#define MB_STRONG strong
|
||||
#else
|
||||
#define MB_STRONG retain
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MB_WEAK
|
||||
#if __has_feature(objc_arc_weak)
|
||||
#define MB_WEAK weak
|
||||
#elif __has_feature(objc_arc)
|
||||
#define MB_WEAK unsafe_unretained
|
||||
#else
|
||||
#define MB_WEAK assign
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
typedef void (^MBProgressHUDCompletionBlock)();
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Displays a simple HUD window containing a progress indicator and two optional labels for short messages.
|
||||
*
|
||||
* This is a simple drop-in class for displaying a progress HUD view similar to Apple's private UIProgressHUD class.
|
||||
* The MBProgressHUD window spans over the entire space given to it by the initWithFrame constructor and catches all
|
||||
* user input on this region, thereby preventing the user operations on components below the view. The HUD itself is
|
||||
* drawn centered as a rounded semi-transparent view which resizes depending on the user specified content.
|
||||
*
|
||||
* This view supports four modes of operation:
|
||||
* - MBProgressHUDModeIndeterminate - shows a UIActivityIndicatorView
|
||||
* - MBProgressHUDModeDeterminate - shows a custom round progress indicator
|
||||
* - MBProgressHUDModeAnnularDeterminate - shows a custom annular progress indicator
|
||||
* - MBProgressHUDModeCustomView - shows an arbitrary, user specified view (@see customView)
|
||||
*
|
||||
* All three modes can have optional labels assigned:
|
||||
* - If the labelText property is set and non-empty then a label containing the provided content is placed below the
|
||||
* indicator view.
|
||||
* - If also the detailsLabelText property is set then another label is placed below the first label.
|
||||
*/
|
||||
@interface MBProgressHUD : UIView
|
||||
|
||||
/**
|
||||
* Creates a new HUD, adds it to provided view and shows it. The counterpart to this method is hideHUDForView:animated:.
|
||||
*
|
||||
* @param view The view that the HUD will be added to
|
||||
* @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use
|
||||
* animations while appearing.
|
||||
* @return A reference to the created HUD.
|
||||
*
|
||||
* @see hideHUDForView:animated:
|
||||
* @see animationType
|
||||
*/
|
||||
+ (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view animated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
* Finds the top-most HUD subview and hides it. The counterpart to this method is showHUDAddedTo:animated:.
|
||||
*
|
||||
* @param view The view that is going to be searched for a HUD subview.
|
||||
* @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use
|
||||
* animations while disappearing.
|
||||
* @return YES if a HUD was found and removed, NO otherwise.
|
||||
*
|
||||
* @see showHUDAddedTo:animated:
|
||||
* @see animationType
|
||||
*/
|
||||
+ (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
* Finds all the HUD subviews and hides them.
|
||||
*
|
||||
* @param view The view that is going to be searched for HUD subviews.
|
||||
* @param animated If set to YES the HUDs will disappear using the current animationType. If set to NO the HUDs will not use
|
||||
* animations while disappearing.
|
||||
* @return the number of HUDs found and removed.
|
||||
*
|
||||
* @see hideHUDForView:animated:
|
||||
* @see animationType
|
||||
*/
|
||||
+ (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
* Finds the top-most HUD subview and returns it.
|
||||
*
|
||||
* @param view The view that is going to be searched.
|
||||
* @return A reference to the last HUD subview discovered.
|
||||
*/
|
||||
+ (MB_INSTANCETYPE)HUDForView:(UIView *)view;
|
||||
|
||||
/**
|
||||
* Finds all HUD subviews and returns them.
|
||||
*
|
||||
* @param view The view that is going to be searched.
|
||||
* @return All found HUD views (array of MBProgressHUD objects).
|
||||
*/
|
||||
+ (NSArray *)allHUDsForView:(UIView *)view;
|
||||
|
||||
/**
|
||||
* A convenience constructor that initializes the HUD with the window's bounds. Calls the designated constructor with
|
||||
* window.bounds as the parameter.
|
||||
*
|
||||
* @param window The window instance that will provide the bounds for the HUD. Should be the same instance as
|
||||
* the HUD's superview (i.e., the window that the HUD will be added to).
|
||||
*/
|
||||
- (id)initWithWindow:(UIWindow *)window;
|
||||
|
||||
/**
|
||||
* A convenience constructor that initializes the HUD with the view's bounds. Calls the designated constructor with
|
||||
* view.bounds as the parameter
|
||||
*
|
||||
* @param view The view instance that will provide the bounds for the HUD. Should be the same instance as
|
||||
* the HUD's superview (i.e., the view that the HUD will be added to).
|
||||
*/
|
||||
- (id)initWithView:(UIView *)view;
|
||||
|
||||
/**
|
||||
* Display the HUD. You need to make sure that the main thread completes its run loop soon after this method call so
|
||||
* the user interface can be updated. Call this method when your task is already set-up to be executed in a new thread
|
||||
* (e.g., when using something like NSOperation or calling an asynchronous call like NSURLRequest).
|
||||
*
|
||||
* @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use
|
||||
* animations while appearing.
|
||||
*
|
||||
* @see animationType
|
||||
*/
|
||||
- (void)show:(BOOL)animated;
|
||||
|
||||
/**
|
||||
* Hide the HUD. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to
|
||||
* hide the HUD when your task completes.
|
||||
*
|
||||
* @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use
|
||||
* animations while disappearing.
|
||||
*
|
||||
* @see animationType
|
||||
*/
|
||||
- (void)hide:(BOOL)animated;
|
||||
|
||||
/**
|
||||
* Hide the HUD after a delay. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to
|
||||
* hide the HUD when your task completes.
|
||||
*
|
||||
* @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use
|
||||
* animations while disappearing.
|
||||
* @param delay Delay in seconds until the HUD is hidden.
|
||||
*
|
||||
* @see animationType
|
||||
*/
|
||||
- (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay;
|
||||
|
||||
/**
|
||||
* Shows the HUD while a background task is executing in a new thread, then hides the HUD.
|
||||
*
|
||||
* This method also takes care of autorelease pools so your method does not have to be concerned with setting up a
|
||||
* pool.
|
||||
*
|
||||
* @param method The method to be executed while the HUD is shown. This method will be executed in a new thread.
|
||||
* @param target The object that the target method belongs to.
|
||||
* @param object An optional object to be passed to the method.
|
||||
* @param animated If set to YES the HUD will (dis)appear using the current animationType. If set to NO the HUD will not use
|
||||
* animations while (dis)appearing.
|
||||
*/
|
||||
- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated;
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
|
||||
/**
|
||||
* Shows the HUD while a block is executing on a background queue, then hides the HUD.
|
||||
*
|
||||
* @see showAnimated:whileExecutingBlock:onQueue:completionBlock:
|
||||
*/
|
||||
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block;
|
||||
|
||||
/**
|
||||
* Shows the HUD while a block is executing on a background queue, then hides the HUD.
|
||||
*
|
||||
* @see showAnimated:whileExecutingBlock:onQueue:completionBlock:
|
||||
*/
|
||||
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(MBProgressHUDCompletionBlock)completion;
|
||||
|
||||
/**
|
||||
* Shows the HUD while a block is executing on the specified dispatch queue, then hides the HUD.
|
||||
*
|
||||
* @see showAnimated:whileExecutingBlock:onQueue:completionBlock:
|
||||
*/
|
||||
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue;
|
||||
|
||||
/**
|
||||
* Shows the HUD while a block is executing on the specified dispatch queue, executes completion block on the main queue, and then hides the HUD.
|
||||
*
|
||||
* @param animated If set to YES the HUD will (dis)appear using the current animationType. If set to NO the HUD will
|
||||
* not use animations while (dis)appearing.
|
||||
* @param block The block to be executed while the HUD is shown.
|
||||
* @param queue The dispatch queue on which the block should be executed.
|
||||
* @param completion The block to be executed on completion.
|
||||
*
|
||||
* @see completionBlock
|
||||
*/
|
||||
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue
|
||||
completionBlock:(MBProgressHUDCompletionBlock)completion;
|
||||
|
||||
/**
|
||||
* A block that gets called after the HUD was completely hidden.
|
||||
*/
|
||||
@property (copy) MBProgressHUDCompletionBlock completionBlock;
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* MBProgressHUD operation mode. The default is MBProgressHUDModeIndeterminate.
|
||||
*
|
||||
* @see MBProgressHUDMode
|
||||
*/
|
||||
@property (assign) MBProgressHUDMode mode;
|
||||
|
||||
/**
|
||||
* The animation type that should be used when the HUD is shown and hidden.
|
||||
*
|
||||
* @see MBProgressHUDAnimation
|
||||
*/
|
||||
@property (assign) MBProgressHUDAnimation animationType;
|
||||
|
||||
/**
|
||||
* The UIView (e.g., a UIImageView) to be shown when the HUD is in MBProgressHUDModeCustomView.
|
||||
* For best results use a 37 by 37 pixel view (so the bounds match the built in indicator bounds).
|
||||
*/
|
||||
@property (MB_STRONG) UIView *customView;
|
||||
|
||||
/**
|
||||
* The HUD delegate object.
|
||||
*
|
||||
* @see MBProgressHUDDelegate
|
||||
*/
|
||||
@property (MB_WEAK) id<MBProgressHUDDelegate> delegate;
|
||||
|
||||
/**
|
||||
* An optional short message to be displayed below the activity indicator. The HUD is automatically resized to fit
|
||||
* the entire text. If the text is too long it will get clipped by displaying "..." at the end. If left unchanged or
|
||||
* set to @"", then no message is displayed.
|
||||
*/
|
||||
@property (copy) NSString *labelText;
|
||||
|
||||
/**
|
||||
* An optional details message displayed below the labelText message. This message is displayed only if the labelText
|
||||
* property is also set and is different from an empty string (@""). The details text can span multiple lines.
|
||||
*/
|
||||
@property (copy) NSString *detailsLabelText;
|
||||
|
||||
/**
|
||||
* The opacity of the HUD window. Defaults to 0.8 (80% opacity).
|
||||
*/
|
||||
@property (assign) float opacity;
|
||||
|
||||
/**
|
||||
* The color of the HUD window. Defaults to black. If this property is set, color is set using
|
||||
* this UIColor and the opacity property is not used. using retain because performing copy on
|
||||
* UIColor base colors (like [UIColor greenColor]) cause problems with the copyZone.
|
||||
*/
|
||||
@property (MB_STRONG) UIColor *color;
|
||||
|
||||
/**
|
||||
* The x-axis offset of the HUD relative to the centre of the superview.
|
||||
*/
|
||||
@property (assign) float xOffset;
|
||||
|
||||
/**
|
||||
* The y-axis offset of the HUD relative to the centre of the superview.
|
||||
*/
|
||||
@property (assign) float yOffset;
|
||||
|
||||
/**
|
||||
* The amount of space between the HUD edge and the HUD elements (labels, indicators or custom views).
|
||||
* Defaults to 20.0
|
||||
*/
|
||||
@property (assign) float margin;
|
||||
|
||||
/**
|
||||
* Cover the HUD background view with a radial gradient.
|
||||
*/
|
||||
@property (assign) BOOL dimBackground;
|
||||
|
||||
/*
|
||||
* Grace period is the time (in seconds) that the invoked method may be run without
|
||||
* showing the HUD. If the task finishes before the grace time runs out, the HUD will
|
||||
* not be shown at all.
|
||||
* This may be used to prevent HUD display for very short tasks.
|
||||
* Defaults to 0 (no grace time).
|
||||
* Grace time functionality is only supported when the task status is known!
|
||||
* @see taskInProgress
|
||||
*/
|
||||
@property (assign) float graceTime;
|
||||
|
||||
/**
|
||||
* The minimum time (in seconds) that the HUD is shown.
|
||||
* This avoids the problem of the HUD being shown and than instantly hidden.
|
||||
* Defaults to 0 (no minimum show time).
|
||||
*/
|
||||
@property (assign) float minShowTime;
|
||||
|
||||
/**
|
||||
* Indicates that the executed operation is in progress. Needed for correct graceTime operation.
|
||||
* If you don't set a graceTime (different than 0.0) this does nothing.
|
||||
* This property is automatically set when using showWhileExecuting:onTarget:withObject:animated:.
|
||||
* When threading is done outside of the HUD (i.e., when the show: and hide: methods are used directly),
|
||||
* you need to set this property when your task starts and completes in order to have normal graceTime
|
||||
* functionality.
|
||||
*/
|
||||
@property (assign) BOOL taskInProgress;
|
||||
|
||||
/**
|
||||
* Removes the HUD from its parent view when hidden.
|
||||
* Defaults to NO.
|
||||
*/
|
||||
@property (assign) BOOL removeFromSuperViewOnHide;
|
||||
|
||||
/**
|
||||
* Font to be used for the main label. Set this property if the default is not adequate.
|
||||
*/
|
||||
@property (MB_STRONG) UIFont* labelFont;
|
||||
|
||||
/**
|
||||
* Font to be used for the details label. Set this property if the default is not adequate.
|
||||
*/
|
||||
@property (MB_STRONG) UIFont* detailsLabelFont;
|
||||
|
||||
/**
|
||||
* The progress of the progress indicator, from 0.0 to 1.0. Defaults to 0.0.
|
||||
*/
|
||||
@property (assign) float progress;
|
||||
|
||||
/**
|
||||
* The minimum size of the HUD bezel. Defaults to CGSizeZero (no minimum size).
|
||||
*/
|
||||
@property (assign) CGSize minSize;
|
||||
|
||||
/**
|
||||
* Force the HUD dimensions to be equal if possible.
|
||||
*/
|
||||
@property (assign, getter = isSquare) BOOL square;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@protocol MBProgressHUDDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
* Called after the HUD was fully hidden from the screen.
|
||||
*/
|
||||
- (void)hudWasHidden:(MBProgressHUD *)hud;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/**
|
||||
* A progress view for showing definite progress by filling up a circle (pie chart).
|
||||
*/
|
||||
@interface MBRoundProgressView : UIView
|
||||
|
||||
/**
|
||||
* Progress (0.0 to 1.0)
|
||||
*/
|
||||
@property (nonatomic, assign) float progress;
|
||||
|
||||
/**
|
||||
* Indicator progress color.
|
||||
* Defaults to white [UIColor whiteColor]
|
||||
*/
|
||||
@property (nonatomic, MB_STRONG) UIColor *progressTintColor;
|
||||
|
||||
/**
|
||||
* Indicator background (non-progress) color.
|
||||
* Defaults to translucent white (alpha 0.1)
|
||||
*/
|
||||
@property (nonatomic, MB_STRONG) UIColor *backgroundTintColor;
|
||||
|
||||
/*
|
||||
* Display mode - NO = round or YES = annular. Defaults to round.
|
||||
*/
|
||||
@property (nonatomic, assign, getter = isAnnular) BOOL annular;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/**
|
||||
* A flat bar progress view.
|
||||
*/
|
||||
@interface MBBarProgressView : UIView
|
||||
|
||||
/**
|
||||
* Progress (0.0 to 1.0)
|
||||
*/
|
||||
@property (nonatomic, assign) float progress;
|
||||
|
||||
/**
|
||||
* Bar border line color.
|
||||
* Defaults to white [UIColor whiteColor].
|
||||
*/
|
||||
@property (nonatomic, MB_STRONG) UIColor *lineColor;
|
||||
|
||||
/**
|
||||
* Bar background color.
|
||||
* Defaults to clear [UIColor clearColor];
|
||||
*/
|
||||
@property (nonatomic, MB_STRONG) UIColor *progressRemainingColor;
|
||||
|
||||
/**
|
||||
* Bar progress color.
|
||||
* Defaults to white [UIColor whiteColor].
|
||||
*/
|
||||
@property (nonatomic, MB_STRONG) UIColor *progressColor;
|
||||
|
||||
@end
|
|
@ -0,0 +1,994 @@
|
|||
//
|
||||
// MBProgressHUD.m
|
||||
// Version 0.7
|
||||
// Created by Matej Bukovinski on 2.4.09.
|
||||
//
|
||||
|
||||
#import "MBProgressHUD.h"
|
||||
|
||||
|
||||
#if __has_feature(objc_arc)
|
||||
#define MB_AUTORELEASE(exp) exp
|
||||
#define MB_RELEASE(exp) exp
|
||||
#define MB_RETAIN(exp) exp
|
||||
#else
|
||||
#define MB_AUTORELEASE(exp) [exp autorelease]
|
||||
#define MB_RELEASE(exp) [exp release]
|
||||
#define MB_RETAIN(exp) [exp retain]
|
||||
#endif
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000
|
||||
#define MBLabelAlignmentCenter NSTextAlignmentCenter
|
||||
#else
|
||||
#define MBLabelAlignmentCenter UITextAlignmentCenter
|
||||
#endif
|
||||
|
||||
|
||||
static const CGFloat kPadding = 4.f;
|
||||
static const CGFloat kLabelFontSize = 16.f;
|
||||
static const CGFloat kDetailsLabelFontSize = 12.f;
|
||||
|
||||
|
||||
@interface MBProgressHUD ()
|
||||
|
||||
- (void)setupLabels;
|
||||
- (void)registerForKVO;
|
||||
- (void)unregisterFromKVO;
|
||||
- (NSArray *)observableKeypaths;
|
||||
- (void)registerForNotifications;
|
||||
- (void)unregisterFromNotifications;
|
||||
- (void)updateUIForKeypath:(NSString *)keyPath;
|
||||
- (void)hideUsingAnimation:(BOOL)animated;
|
||||
- (void)showUsingAnimation:(BOOL)animated;
|
||||
- (void)done;
|
||||
- (void)updateIndicators;
|
||||
- (void)handleGraceTimer:(NSTimer *)theTimer;
|
||||
- (void)handleMinShowTimer:(NSTimer *)theTimer;
|
||||
- (void)setTransformForCurrentOrientation:(BOOL)animated;
|
||||
- (void)cleanUp;
|
||||
- (void)launchExecution;
|
||||
- (void)deviceOrientationDidChange:(NSNotification *)notification;
|
||||
- (void)hideDelayed:(NSNumber *)animated;
|
||||
|
||||
@property (atomic, MB_STRONG) UIView *indicator;
|
||||
@property (atomic, MB_STRONG) NSTimer *graceTimer;
|
||||
@property (atomic, MB_STRONG) NSTimer *minShowTimer;
|
||||
@property (atomic, MB_STRONG) NSDate *showStarted;
|
||||
@property (atomic, assign) CGSize size;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation MBProgressHUD {
|
||||
BOOL useAnimation;
|
||||
SEL methodForExecution;
|
||||
id targetForExecution;
|
||||
id objectForExecution;
|
||||
UILabel *label;
|
||||
UILabel *detailsLabel;
|
||||
BOOL isFinished;
|
||||
CGAffineTransform rotationTransform;
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
@synthesize animationType;
|
||||
@synthesize delegate;
|
||||
@synthesize opacity;
|
||||
@synthesize color;
|
||||
@synthesize labelFont;
|
||||
@synthesize detailsLabelFont;
|
||||
@synthesize indicator;
|
||||
@synthesize xOffset;
|
||||
@synthesize yOffset;
|
||||
@synthesize minSize;
|
||||
@synthesize square;
|
||||
@synthesize margin;
|
||||
@synthesize dimBackground;
|
||||
@synthesize graceTime;
|
||||
@synthesize minShowTime;
|
||||
@synthesize graceTimer;
|
||||
@synthesize minShowTimer;
|
||||
@synthesize taskInProgress;
|
||||
@synthesize removeFromSuperViewOnHide;
|
||||
@synthesize customView;
|
||||
@synthesize showStarted;
|
||||
@synthesize mode;
|
||||
@synthesize labelText;
|
||||
@synthesize detailsLabelText;
|
||||
@synthesize progress;
|
||||
@synthesize size;
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
@synthesize completionBlock;
|
||||
#endif
|
||||
|
||||
#pragma mark - Class methods
|
||||
|
||||
+ (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view animated:(BOOL)animated {
|
||||
MBProgressHUD *hud = [[self alloc] initWithView:view];
|
||||
[view addSubview:hud];
|
||||
[hud show:animated];
|
||||
return MB_AUTORELEASE(hud);
|
||||
}
|
||||
|
||||
+ (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated {
|
||||
MBProgressHUD *hud = [self HUDForView:view];
|
||||
if (hud != nil) {
|
||||
hud.removeFromSuperViewOnHide = YES;
|
||||
[hud hide:animated];
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated {
|
||||
NSArray *huds = [MBProgressHUD allHUDsForView:view];
|
||||
for (MBProgressHUD *hud in huds) {
|
||||
hud.removeFromSuperViewOnHide = YES;
|
||||
[hud hide:animated];
|
||||
}
|
||||
return [huds count];
|
||||
}
|
||||
|
||||
+ (MB_INSTANCETYPE)HUDForView:(UIView *)view {
|
||||
NSEnumerator *subviewsEnum = [view.subviews reverseObjectEnumerator];
|
||||
for (UIView *subview in subviewsEnum) {
|
||||
if ([subview isKindOfClass:self]) {
|
||||
return (MBProgressHUD *)subview;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (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)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
// Set default values for properties
|
||||
self.animationType = MBProgressHUDAnimationFade;
|
||||
self.mode = MBProgressHUDModeIndeterminate;
|
||||
self.labelText = nil;
|
||||
self.detailsLabelText = nil;
|
||||
self.opacity = 0.8f;
|
||||
self.color = nil;
|
||||
self.labelFont = [UIFont boldSystemFontOfSize:kLabelFontSize];
|
||||
self.detailsLabelFont = [UIFont boldSystemFontOfSize:kDetailsLabelFontSize];
|
||||
self.xOffset = 0.0f;
|
||||
self.yOffset = 0.0f;
|
||||
self.dimBackground = NO;
|
||||
self.margin = 20.0f;
|
||||
self.graceTime = 0.0f;
|
||||
self.minShowTime = 0.0f;
|
||||
self.removeFromSuperViewOnHide = NO;
|
||||
self.minSize = CGSizeZero;
|
||||
self.square = NO;
|
||||
self.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin
|
||||
| UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
|
||||
|
||||
// Transparent background
|
||||
self.opaque = NO;
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
// Make it invisible for now
|
||||
self.alpha = 0.0f;
|
||||
|
||||
taskInProgress = NO;
|
||||
rotationTransform = CGAffineTransformIdentity;
|
||||
|
||||
[self setupLabels];
|
||||
[self updateIndicators];
|
||||
[self registerForKVO];
|
||||
[self registerForNotifications];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithView:(UIView *)view {
|
||||
NSAssert(view, @"View must not be nil.");
|
||||
return [self initWithFrame:view.bounds];
|
||||
}
|
||||
|
||||
- (id)initWithWindow:(UIWindow *)window {
|
||||
return [self initWithView:window];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self unregisterFromNotifications];
|
||||
[self unregisterFromKVO];
|
||||
#if !__has_feature(objc_arc)
|
||||
[color release];
|
||||
[indicator release];
|
||||
[label release];
|
||||
[detailsLabel release];
|
||||
[labelText release];
|
||||
[detailsLabelText release];
|
||||
[graceTimer release];
|
||||
[minShowTimer release];
|
||||
[showStarted release];
|
||||
[customView release];
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
[completionBlock release];
|
||||
#endif
|
||||
[super dealloc];
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma mark - Show & hide
|
||||
|
||||
- (void)show:(BOOL)animated {
|
||||
useAnimation = animated;
|
||||
// If the grace time is set postpone the HUD display
|
||||
if (self.graceTime > 0.0) {
|
||||
self.graceTimer = [NSTimer scheduledTimerWithTimeInterval:self.graceTime target:self
|
||||
selector:@selector(handleGraceTimer:) userInfo:nil repeats:NO];
|
||||
}
|
||||
// ... otherwise show the HUD imediately
|
||||
else {
|
||||
[self setNeedsDisplay];
|
||||
[self showUsingAnimation:useAnimation];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)hide:(BOOL)animated {
|
||||
useAnimation = animated;
|
||||
// If the minShow time is set, calculate how long the hud was shown,
|
||||
// and pospone the hiding operation if necessary
|
||||
if (self.minShowTime > 0.0 && showStarted) {
|
||||
NSTimeInterval interv = [[NSDate date] timeIntervalSinceDate:showStarted];
|
||||
if (interv < self.minShowTime) {
|
||||
self.minShowTimer = [NSTimer scheduledTimerWithTimeInterval:(self.minShowTime - interv) target:self
|
||||
selector:@selector(handleMinShowTimer:) userInfo:nil repeats:NO];
|
||||
return;
|
||||
}
|
||||
}
|
||||
// ... otherwise hide the HUD immediately
|
||||
[self hideUsingAnimation:useAnimation];
|
||||
}
|
||||
|
||||
- (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay {
|
||||
[self performSelector:@selector(hideDelayed:) withObject:[NSNumber numberWithBool:animated] afterDelay:delay];
|
||||
}
|
||||
|
||||
- (void)hideDelayed:(NSNumber *)animated {
|
||||
[self hide:[animated boolValue]];
|
||||
}
|
||||
|
||||
#pragma mark - Timer callbacks
|
||||
|
||||
- (void)handleGraceTimer:(NSTimer *)theTimer {
|
||||
// Show the HUD only if the task is still running
|
||||
if (taskInProgress) {
|
||||
[self setNeedsDisplay];
|
||||
[self showUsingAnimation:useAnimation];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleMinShowTimer:(NSTimer *)theTimer {
|
||||
[self hideUsingAnimation:useAnimation];
|
||||
}
|
||||
|
||||
#pragma mark - View Hierrarchy
|
||||
|
||||
- (void)didMoveToSuperview {
|
||||
// We need to take care of rotation ourselfs if we're adding the HUD to a window
|
||||
if ([self.superview isKindOfClass:[UIWindow class]]) {
|
||||
[self setTransformForCurrentOrientation:NO];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Internal show & hide operations
|
||||
|
||||
- (void)showUsingAnimation:(BOOL)animated {
|
||||
if (animated && animationType == MBProgressHUDAnimationZoomIn) {
|
||||
self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(0.5f, 0.5f));
|
||||
} else if (animated && animationType == MBProgressHUDAnimationZoomOut) {
|
||||
self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(1.5f, 1.5f));
|
||||
}
|
||||
self.showStarted = [NSDate date];
|
||||
// Fade in
|
||||
if (animated) {
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationDuration:0.30];
|
||||
self.alpha = 1.0f;
|
||||
if (animationType == MBProgressHUDAnimationZoomIn || animationType == MBProgressHUDAnimationZoomOut) {
|
||||
self.transform = rotationTransform;
|
||||
}
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
else {
|
||||
self.alpha = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)hideUsingAnimation:(BOOL)animated {
|
||||
// Fade out
|
||||
if (animated && showStarted) {
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationDuration:0.30];
|
||||
[UIView setAnimationDelegate:self];
|
||||
[UIView setAnimationDidStopSelector:@selector(animationFinished:finished:context:)];
|
||||
// 0.02 prevents the hud from passing through touches during the animation the hud will get completely hidden
|
||||
// in the done method
|
||||
if (animationType == MBProgressHUDAnimationZoomIn) {
|
||||
self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(1.5f, 1.5f));
|
||||
} else if (animationType == MBProgressHUDAnimationZoomOut) {
|
||||
self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(0.5f, 0.5f));
|
||||
}
|
||||
|
||||
self.alpha = 0.02f;
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
else {
|
||||
self.alpha = 0.0f;
|
||||
[self done];
|
||||
}
|
||||
self.showStarted = nil;
|
||||
}
|
||||
|
||||
- (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void*)context {
|
||||
[self done];
|
||||
}
|
||||
|
||||
- (void)done {
|
||||
isFinished = YES;
|
||||
self.alpha = 0.0f;
|
||||
if ([delegate respondsToSelector:@selector(hudWasHidden:)]) {
|
||||
[delegate performSelector:@selector(hudWasHidden:) withObject:self];
|
||||
}
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
if (self.completionBlock) {
|
||||
self.completionBlock();
|
||||
self.completionBlock = NULL;
|
||||
}
|
||||
#endif
|
||||
if (removeFromSuperViewOnHide) {
|
||||
[self removeFromSuperview];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Threading
|
||||
|
||||
- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated {
|
||||
methodForExecution = method;
|
||||
targetForExecution = MB_RETAIN(target);
|
||||
objectForExecution = MB_RETAIN(object);
|
||||
// Launch execution in new thread
|
||||
self.taskInProgress = YES;
|
||||
[NSThread detachNewThreadSelector:@selector(launchExecution) toTarget:self withObject:nil];
|
||||
// Show HUD view
|
||||
[self show:animated];
|
||||
}
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
|
||||
- (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 (^)())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:(MBProgressHUDCompletionBlock)completion {
|
||||
self.taskInProgress = YES;
|
||||
self.completionBlock = completion;
|
||||
dispatch_async(queue, ^(void) {
|
||||
block();
|
||||
dispatch_async(dispatch_get_main_queue(), ^(void) {
|
||||
[self cleanUp];
|
||||
});
|
||||
});
|
||||
[self show:animated];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
- (void)launchExecution {
|
||||
@autoreleasepool {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
// Start executing the requested task
|
||||
[targetForExecution performSelector:methodForExecution withObject:objectForExecution];
|
||||
#pragma clang diagnostic pop
|
||||
// Task completed, update view in main thread (note: view operations should
|
||||
// be done only in the main thread)
|
||||
[self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cleanUp {
|
||||
taskInProgress = NO;
|
||||
self.indicator = nil;
|
||||
#if !__has_feature(objc_arc)
|
||||
[targetForExecution release];
|
||||
[objectForExecution release];
|
||||
#else
|
||||
targetForExecution = nil;
|
||||
objectForExecution = nil;
|
||||
#endif
|
||||
[self hide:useAnimation];
|
||||
}
|
||||
|
||||
#pragma mark - UI
|
||||
|
||||
- (void)setupLabels {
|
||||
label = [[UILabel alloc] initWithFrame:self.bounds];
|
||||
label.adjustsFontSizeToFitWidth = NO;
|
||||
label.textAlignment = MBLabelAlignmentCenter;
|
||||
label.opaque = NO;
|
||||
label.backgroundColor = [UIColor clearColor];
|
||||
label.textColor = [UIColor whiteColor];
|
||||
label.font = self.labelFont;
|
||||
label.text = self.labelText;
|
||||
[self addSubview:label];
|
||||
|
||||
detailsLabel = [[UILabel alloc] initWithFrame:self.bounds];
|
||||
detailsLabel.font = self.detailsLabelFont;
|
||||
detailsLabel.adjustsFontSizeToFitWidth = NO;
|
||||
detailsLabel.textAlignment = MBLabelAlignmentCenter;
|
||||
detailsLabel.opaque = NO;
|
||||
detailsLabel.backgroundColor = [UIColor clearColor];
|
||||
detailsLabel.textColor = [UIColor whiteColor];
|
||||
detailsLabel.numberOfLines = 0;
|
||||
detailsLabel.font = self.detailsLabelFont;
|
||||
detailsLabel.text = self.detailsLabelText;
|
||||
[self addSubview:detailsLabel];
|
||||
}
|
||||
|
||||
- (void)updateIndicators {
|
||||
|
||||
BOOL isActivityIndicator = [indicator isKindOfClass:[UIActivityIndicatorView class]];
|
||||
BOOL isRoundIndicator = [indicator isKindOfClass:[MBRoundProgressView class]];
|
||||
|
||||
if (mode == MBProgressHUDModeIndeterminate && !isActivityIndicator) {
|
||||
// Update to indeterminate indicator
|
||||
[indicator removeFromSuperview];
|
||||
self.indicator = MB_AUTORELEASE([[UIActivityIndicatorView alloc]
|
||||
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]);
|
||||
[(UIActivityIndicatorView *)indicator startAnimating];
|
||||
[self addSubview:indicator];
|
||||
}
|
||||
else if (mode == MBProgressHUDModeDeterminateHorizontalBar) {
|
||||
// Update to bar determinate indicator
|
||||
[indicator removeFromSuperview];
|
||||
self.indicator = MB_AUTORELEASE([[MBBarProgressView alloc] init]);
|
||||
[self addSubview:indicator];
|
||||
}
|
||||
else if (mode == MBProgressHUDModeDeterminate || mode == MBProgressHUDModeAnnularDeterminate) {
|
||||
if (!isRoundIndicator) {
|
||||
// Update to determinante indicator
|
||||
[indicator removeFromSuperview];
|
||||
self.indicator = MB_AUTORELEASE([[MBRoundProgressView alloc] init]);
|
||||
[self addSubview:indicator];
|
||||
}
|
||||
if (mode == MBProgressHUDModeAnnularDeterminate) {
|
||||
[(MBRoundProgressView *)indicator setAnnular:YES];
|
||||
}
|
||||
}
|
||||
else if (mode == MBProgressHUDModeCustomView && customView != indicator) {
|
||||
// Update custom view indicator
|
||||
[indicator removeFromSuperview];
|
||||
self.indicator = customView;
|
||||
[self addSubview:indicator];
|
||||
} else if (mode == MBProgressHUDModeText) {
|
||||
[indicator removeFromSuperview];
|
||||
self.indicator = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Layout
|
||||
|
||||
- (void)layoutSubviews {
|
||||
|
||||
// Entirely cover the parent view
|
||||
UIView *parent = self.superview;
|
||||
if (parent) {
|
||||
self.frame = parent.bounds;
|
||||
}
|
||||
CGRect bounds = self.bounds;
|
||||
|
||||
// Determine the total widt and height needed
|
||||
CGFloat maxWidth = bounds.size.width - 4 * margin;
|
||||
CGSize totalSize = CGSizeZero;
|
||||
|
||||
CGRect indicatorF = indicator.bounds;
|
||||
indicatorF.size.width = MIN(indicatorF.size.width, maxWidth);
|
||||
totalSize.width = MAX(totalSize.width, indicatorF.size.width);
|
||||
totalSize.height += indicatorF.size.height;
|
||||
|
||||
CGSize labelSize = [label.text sizeWithFont:label.font];
|
||||
labelSize.width = MIN(labelSize.width, maxWidth);
|
||||
totalSize.width = MAX(totalSize.width, labelSize.width);
|
||||
totalSize.height += labelSize.height;
|
||||
if (labelSize.height > 0.f && indicatorF.size.height > 0.f) {
|
||||
totalSize.height += kPadding;
|
||||
}
|
||||
|
||||
CGFloat remainingHeight = bounds.size.height - totalSize.height - kPadding - 4 * margin;
|
||||
CGSize maxSize = CGSizeMake(maxWidth, remainingHeight);
|
||||
CGSize detailsLabelSize = [detailsLabel.text sizeWithFont:detailsLabel.font
|
||||
constrainedToSize:maxSize lineBreakMode:detailsLabel.lineBreakMode];
|
||||
totalSize.width = MAX(totalSize.width, detailsLabelSize.width);
|
||||
totalSize.height += detailsLabelSize.height;
|
||||
if (detailsLabelSize.height > 0.f && (indicatorF.size.height > 0.f || labelSize.height > 0.f)) {
|
||||
totalSize.height += kPadding;
|
||||
}
|
||||
|
||||
totalSize.width += 2 * margin;
|
||||
totalSize.height += 2 * margin;
|
||||
|
||||
// Position elements
|
||||
CGFloat yPos = roundf(((bounds.size.height - totalSize.height) / 2)) + margin + yOffset;
|
||||
CGFloat xPos = xOffset;
|
||||
indicatorF.origin.y = yPos;
|
||||
indicatorF.origin.x = roundf((bounds.size.width - indicatorF.size.width) / 2) + xPos;
|
||||
indicator.frame = indicatorF;
|
||||
yPos += indicatorF.size.height;
|
||||
|
||||
if (labelSize.height > 0.f && indicatorF.size.height > 0.f) {
|
||||
yPos += kPadding;
|
||||
}
|
||||
CGRect labelF;
|
||||
labelF.origin.y = yPos;
|
||||
labelF.origin.x = roundf((bounds.size.width - labelSize.width) / 2) + xPos;
|
||||
labelF.size = labelSize;
|
||||
label.frame = labelF;
|
||||
yPos += labelF.size.height;
|
||||
|
||||
if (detailsLabelSize.height > 0.f && (indicatorF.size.height > 0.f || labelSize.height > 0.f)) {
|
||||
yPos += kPadding;
|
||||
}
|
||||
CGRect detailsLabelF;
|
||||
detailsLabelF.origin.y = yPos;
|
||||
detailsLabelF.origin.x = roundf((bounds.size.width - detailsLabelSize.width) / 2) + xPos;
|
||||
detailsLabelF.size = detailsLabelSize;
|
||||
detailsLabel.frame = detailsLabelF;
|
||||
|
||||
// Enforce minsize and quare rules
|
||||
if (square) {
|
||||
CGFloat max = MAX(totalSize.width, totalSize.height);
|
||||
if (max <= bounds.size.width - 2 * margin) {
|
||||
totalSize.width = max;
|
||||
}
|
||||
if (max <= bounds.size.height - 2 * margin) {
|
||||
totalSize.height = max;
|
||||
}
|
||||
}
|
||||
if (totalSize.width < minSize.width) {
|
||||
totalSize.width = minSize.width;
|
||||
}
|
||||
if (totalSize.height < minSize.height) {
|
||||
totalSize.height = minSize.height;
|
||||
}
|
||||
|
||||
self.size = totalSize;
|
||||
}
|
||||
|
||||
#pragma mark BG Drawing
|
||||
|
||||
- (void)drawRect:(CGRect)rect {
|
||||
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
UIGraphicsPushContext(context);
|
||||
|
||||
if (self.dimBackground) {
|
||||
//Gradient colours
|
||||
size_t gradLocationsNum = 2;
|
||||
CGFloat gradLocations[2] = {0.0f, 1.0f};
|
||||
CGFloat gradColors[8] = {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.75f};
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradColors, gradLocations, gradLocationsNum);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
//Gradient center
|
||||
CGPoint gradCenter= CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
|
||||
//Gradient radius
|
||||
float gradRadius = MIN(self.bounds.size.width , self.bounds.size.height) ;
|
||||
//Gradient draw
|
||||
CGContextDrawRadialGradient (context, gradient, gradCenter,
|
||||
0, gradCenter, gradRadius,
|
||||
kCGGradientDrawsAfterEndLocation);
|
||||
CGGradientRelease(gradient);
|
||||
}
|
||||
|
||||
// Set background rect color
|
||||
if (self.color) {
|
||||
CGContextSetFillColorWithColor(context, self.color.CGColor);
|
||||
} else {
|
||||
CGContextSetGrayFillColor(context, 0.0f, self.opacity);
|
||||
}
|
||||
|
||||
|
||||
// Center HUD
|
||||
CGRect allRect = self.bounds;
|
||||
// Draw rounded HUD backgroud rect
|
||||
CGRect boxRect = CGRectMake(roundf((allRect.size.width - size.width) / 2) + self.xOffset,
|
||||
roundf((allRect.size.height - size.height) / 2) + self.yOffset, size.width, size.height);
|
||||
float radius = 10.0f;
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, CGRectGetMinX(boxRect) + radius, CGRectGetMinY(boxRect));
|
||||
CGContextAddArc(context, CGRectGetMaxX(boxRect) - radius, CGRectGetMinY(boxRect) + radius, radius, 3 * (float)M_PI / 2, 0, 0);
|
||||
CGContextAddArc(context, CGRectGetMaxX(boxRect) - radius, CGRectGetMaxY(boxRect) - radius, radius, 0, (float)M_PI / 2, 0);
|
||||
CGContextAddArc(context, CGRectGetMinX(boxRect) + radius, CGRectGetMaxY(boxRect) - radius, radius, (float)M_PI / 2, (float)M_PI, 0);
|
||||
CGContextAddArc(context, CGRectGetMinX(boxRect) + radius, CGRectGetMinY(boxRect) + radius, radius, (float)M_PI, 3 * (float)M_PI / 2, 0);
|
||||
CGContextClosePath(context);
|
||||
CGContextFillPath(context);
|
||||
|
||||
UIGraphicsPopContext();
|
||||
}
|
||||
|
||||
#pragma mark - KVO
|
||||
|
||||
- (void)registerForKVO {
|
||||
for (NSString *keyPath in [self observableKeypaths]) {
|
||||
[self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unregisterFromKVO {
|
||||
for (NSString *keyPath in [self observableKeypaths]) {
|
||||
[self removeObserver:self forKeyPath:keyPath];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)observableKeypaths {
|
||||
return [NSArray arrayWithObjects:@"mode", @"customView", @"labelText", @"labelFont",
|
||||
@"detailsLabelText", @"detailsLabelFont", @"progress", nil];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
if (![NSThread isMainThread]) {
|
||||
[self performSelectorOnMainThread:@selector(updateUIForKeypath:) withObject:keyPath waitUntilDone:NO];
|
||||
} else {
|
||||
[self updateUIForKeypath:keyPath];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateUIForKeypath:(NSString *)keyPath {
|
||||
if ([keyPath isEqualToString:@"mode"] || [keyPath isEqualToString:@"customView"]) {
|
||||
[self updateIndicators];
|
||||
} else if ([keyPath isEqualToString:@"labelText"]) {
|
||||
label.text = self.labelText;
|
||||
} else if ([keyPath isEqualToString:@"labelFont"]) {
|
||||
label.font = self.labelFont;
|
||||
} else if ([keyPath isEqualToString:@"detailsLabelText"]) {
|
||||
detailsLabel.text = self.detailsLabelText;
|
||||
} else if ([keyPath isEqualToString:@"detailsLabelFont"]) {
|
||||
detailsLabel.font = self.detailsLabelFont;
|
||||
} else if ([keyPath isEqualToString:@"progress"]) {
|
||||
if ([indicator respondsToSelector:@selector(setProgress:)]) {
|
||||
[(id)indicator setProgress:progress];
|
||||
}
|
||||
return;
|
||||
}
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
#pragma mark - Notifications
|
||||
|
||||
- (void)registerForNotifications {
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc addObserver:self selector:@selector(deviceOrientationDidChange:)
|
||||
name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)unregisterFromNotifications {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)deviceOrientationDidChange:(NSNotification *)notification {
|
||||
UIView *superview = self.superview;
|
||||
if (!superview) {
|
||||
return;
|
||||
} else if ([superview isKindOfClass:[UIWindow class]]) {
|
||||
[self setTransformForCurrentOrientation:YES];
|
||||
} else {
|
||||
self.bounds = self.superview.bounds;
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setTransformForCurrentOrientation:(BOOL)animated {
|
||||
// Stay in sync with the superview
|
||||
if (self.superview) {
|
||||
self.bounds = self.superview.bounds;
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
|
||||
CGFloat radians = 0;
|
||||
if (UIInterfaceOrientationIsLandscape(orientation)) {
|
||||
if (orientation == UIInterfaceOrientationLandscapeLeft) { radians = -(CGFloat)M_PI_2; }
|
||||
else { radians = (CGFloat)M_PI_2; }
|
||||
// Window coordinates differ!
|
||||
self.bounds = CGRectMake(0, 0, self.bounds.size.height, self.bounds.size.width);
|
||||
} else {
|
||||
if (orientation == UIInterfaceOrientationPortraitUpsideDown) { radians = (CGFloat)M_PI; }
|
||||
else { radians = 0; }
|
||||
}
|
||||
rotationTransform = CGAffineTransformMakeRotation(radians);
|
||||
|
||||
if (animated) {
|
||||
[UIView beginAnimations:nil context:nil];
|
||||
}
|
||||
[self setTransform:rotationTransform];
|
||||
if (animated) {
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
}
|
||||
|
||||
@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];
|
||||
[self registerForKVO];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self unregisterFromKVO];
|
||||
#if !__has_feature(objc_arc)
|
||||
[_progressTintColor release];
|
||||
[_backgroundTintColor release];
|
||||
[super dealloc];
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma mark - Drawing
|
||||
|
||||
- (void)drawRect:(CGRect)rect {
|
||||
|
||||
CGRect allRect = self.bounds;
|
||||
CGRect circleRect = CGRectInset(allRect, 2.0f, 2.0f);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
if (_annular) {
|
||||
// Draw background
|
||||
CGFloat lineWidth = 5.f;
|
||||
UIBezierPath *processBackgroundPath = [UIBezierPath bezierPath];
|
||||
processBackgroundPath.lineWidth = lineWidth;
|
||||
processBackgroundPath.lineCapStyle = kCGLineCapRound;
|
||||
CGPoint center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
|
||||
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 = kCGLineCapRound;
|
||||
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
|
||||
[_progressTintColor setStroke];
|
||||
[_backgroundTintColor setFill];
|
||||
CGContextSetLineWidth(context, 2.0f);
|
||||
CGContextFillEllipseInRect(context, circleRect);
|
||||
CGContextStrokeEllipseInRect(context, circleRect);
|
||||
// Draw progress
|
||||
CGPoint center = CGPointMake(allRect.size.width / 2, allRect.size.height / 2);
|
||||
CGFloat radius = (allRect.size.width - 4) / 2;
|
||||
CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees
|
||||
CGFloat endAngle = (self.progress * 2 * (float)M_PI) + startAngle;
|
||||
CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 1.0f); // white
|
||||
CGContextMoveToPoint(context, center.x, center.y);
|
||||
CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0);
|
||||
CGContextClosePath(context);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - KVO
|
||||
|
||||
- (void)registerForKVO {
|
||||
for (NSString *keyPath in [self observableKeypaths]) {
|
||||
[self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unregisterFromKVO {
|
||||
for (NSString *keyPath in [self observableKeypaths]) {
|
||||
[self removeObserver:self forKeyPath:keyPath];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)observableKeypaths {
|
||||
return [NSArray arrayWithObjects:@"progressTintColor", @"backgroundTintColor", @"progress", @"annular", nil];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
@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;
|
||||
[self registerForKVO];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self unregisterFromKVO];
|
||||
#if !__has_feature(objc_arc)
|
||||
[_lineColor release];
|
||||
[_progressColor release];
|
||||
[_progressRemainingColor release];
|
||||
[super dealloc];
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma mark - Drawing
|
||||
|
||||
- (void)drawRect:(CGRect)rect {
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
// setup properties
|
||||
CGContextSetLineWidth(context, 2);
|
||||
CGContextSetStrokeColorWithColor(context,[_lineColor CGColor]);
|
||||
CGContextSetFillColorWithColor(context, [_progressRemainingColor CGColor]);
|
||||
|
||||
// draw line border
|
||||
float radius = (rect.size.height / 2) - 2;
|
||||
CGContextMoveToPoint(context, 2, rect.size.height/2);
|
||||
CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius);
|
||||
CGContextAddLineToPoint(context, rect.size.width - radius - 2, 2);
|
||||
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);
|
||||
CGContextAddLineToPoint(context, radius + 2, rect.size.height - 2);
|
||||
CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height/2, radius);
|
||||
CGContextFillPath(context);
|
||||
|
||||
// draw progress background
|
||||
CGContextMoveToPoint(context, 2, rect.size.height/2);
|
||||
CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius);
|
||||
CGContextAddLineToPoint(context, rect.size.width - radius - 2, 2);
|
||||
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);
|
||||
CGContextAddLineToPoint(context, radius + 2, rect.size.height - 2);
|
||||
CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height/2, radius);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
// setup to draw progress color
|
||||
CGContextSetFillColorWithColor(context, [_progressColor CGColor]);
|
||||
radius = radius - 2;
|
||||
float amount = self.progress * rect.size.width;
|
||||
|
||||
// if progress is in the middle area
|
||||
if (amount >= radius + 4 && amount <= (rect.size.width - radius - 4)) {
|
||||
// top
|
||||
CGContextMoveToPoint(context, 4, rect.size.height/2);
|
||||
CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius);
|
||||
CGContextAddLineToPoint(context, amount, 4);
|
||||
CGContextAddLineToPoint(context, amount, radius + 4);
|
||||
|
||||
// bottom
|
||||
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 is in the right arc
|
||||
else if (amount > radius + 4) {
|
||||
float x = amount - (rect.size.width - radius - 4);
|
||||
|
||||
// top
|
||||
CGContextMoveToPoint(context, 4, rect.size.height/2);
|
||||
CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius);
|
||||
CGContextAddLineToPoint(context, rect.size.width - radius - 4, 4);
|
||||
float 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);
|
||||
|
||||
// bottom
|
||||
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) {
|
||||
// top
|
||||
CGContextMoveToPoint(context, 4, rect.size.height/2);
|
||||
CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius);
|
||||
CGContextAddLineToPoint(context, radius + 4, rect.size.height/2);
|
||||
|
||||
// bottom
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - KVO
|
||||
|
||||
- (void)registerForKVO {
|
||||
for (NSString *keyPath in [self observableKeypaths]) {
|
||||
[self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unregisterFromKVO {
|
||||
for (NSString *keyPath in [self observableKeypaths]) {
|
||||
[self removeObserver:self forKeyPath:keyPath];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)observableKeypaths {
|
||||
return [NSArray arrayWithObjects:@"lineColor", @"progressRemainingColor", @"progressColor", @"progress", nil];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
|
||||
File: Reachability.h
|
||||
Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
|
||||
|
||||
Version: 2.0.4ddg
|
||||
*/
|
||||
|
||||
/*
|
||||
Significant additions made by Andrew W. Donoho, August 11, 2009.
|
||||
This is a derived work of Apple's Reachability v2.0 class.
|
||||
|
||||
The below license is the new BSD license with the OSI recommended personalizations.
|
||||
<http://www.opensource.org/licenses/bsd-license.php>
|
||||
|
||||
Extensions Copyright (C) 2009 Donoho Design Group, LLC. All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of Andrew W. Donoho nor Donoho Design Group, L.L.C.
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY DONOHO DESIGN GROUP, L.L.C. "AS IS" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Apple's Original License on Reachability v2.0
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and your
|
||||
use, installation, modification or redistribution of this Apple software
|
||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
||||
please do not use, install, modify or redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject
|
||||
to these terms, Apple grants you a personal, non-exclusive license, under
|
||||
Apple's copyrights in this original Apple software (the "Apple Software"), to
|
||||
use, reproduce, modify and redistribute the Apple Software, with or without
|
||||
modifications, in source and/or binary forms; provided that if you redistribute
|
||||
the Apple Software in its entirety and without modifications, you must retain
|
||||
this notice and the following text and disclaimers in all such redistributions
|
||||
of the Apple Software.
|
||||
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may be used
|
||||
to endorse or promote products derived from the Apple Software without specific
|
||||
prior written permission from Apple. Except as expressly stated in this notice,
|
||||
no other rights or licenses, express or implied, are granted by Apple herein,
|
||||
including but not limited to any patent rights that may be infringed by your
|
||||
derivative works or by other works in which the Apple Software may be
|
||||
incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||
COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
|
||||
DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
|
||||
CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
DDG extensions include:
|
||||
Each reachability object now has a copy of the key used to store it in a
|
||||
dictionary. This allows each observer to quickly determine if the event is
|
||||
important to them.
|
||||
|
||||
-currentReachabilityStatus also has a significantly different decision criteria than
|
||||
Apple's code.
|
||||
|
||||
A multiple convenience test methods have been added.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
#import <netinet/in.h>
|
||||
|
||||
#define USE_DDG_EXTENSIONS 1 // Use DDG's Extensions to test network criteria.
|
||||
// Since NSAssert and NSCAssert are used in this code,
|
||||
// I recommend you set NS_BLOCK_ASSERTIONS=1 in the release versions of your projects.
|
||||
|
||||
enum {
|
||||
|
||||
// DDG NetworkStatus Constant Names.
|
||||
kNotReachable = 0, // Apple's code depends upon 'NotReachable' being the same value as 'NO'.
|
||||
kReachableViaWWAN, // Switched order from Apple's enum. WWAN is active before WiFi.
|
||||
kReachableViaWiFi
|
||||
|
||||
};
|
||||
typedef uint32_t NetworkStatus;
|
||||
|
||||
enum {
|
||||
|
||||
// Apple NetworkStatus Constant Names.
|
||||
NotReachable = kNotReachable,
|
||||
ReachableViaWiFi = kReachableViaWiFi,
|
||||
ReachableViaWWAN = kReachableViaWWAN
|
||||
|
||||
};
|
||||
|
||||
|
||||
extern NSString *const kInternetConnection;
|
||||
extern NSString *const kLocalWiFiConnection;
|
||||
extern NSString *const kReachabilityChangedNotification;
|
||||
|
||||
@interface Reachability: NSObject {
|
||||
|
||||
@private
|
||||
NSString *key_;
|
||||
SCNetworkReachabilityRef reachabilityRef;
|
||||
|
||||
}
|
||||
|
||||
@property (copy) NSString *key; // Atomic because network operations are asynchronous.
|
||||
|
||||
// Designated Initializer.
|
||||
- (Reachability *) initWithReachabilityRef: (SCNetworkReachabilityRef) ref;
|
||||
|
||||
// Use to check the reachability of a particular host name.
|
||||
+ (Reachability *) reachabilityWithHostName: (NSString*) hostName;
|
||||
|
||||
// Use to check the reachability of a particular IP address.
|
||||
+ (Reachability *) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
|
||||
|
||||
// Use to check whether the default route is available.
|
||||
// Should be used to, at minimum, establish network connectivity.
|
||||
+ (Reachability *) reachabilityForInternetConnection;
|
||||
|
||||
// Use to check whether a local wifi connection is available.
|
||||
+ (Reachability *) reachabilityForLocalWiFi;
|
||||
|
||||
//Start listening for reachability notifications on the current run loop.
|
||||
- (BOOL) startNotifier;
|
||||
- (void) stopNotifier;
|
||||
|
||||
// Comparison routines to enable choosing actions in a notification.
|
||||
- (BOOL) isEqual: (Reachability *) r;
|
||||
|
||||
// These are the status tests.
|
||||
- (NetworkStatus) currentReachabilityStatus;
|
||||
|
||||
// The main direct test of reachability.
|
||||
- (BOOL) isReachable;
|
||||
|
||||
// WWAN may be available, but not active until a connection has been established.
|
||||
// WiFi may require a connection for VPN on Demand.
|
||||
- (BOOL) isConnectionRequired; // Identical DDG variant.
|
||||
- (BOOL) connectionRequired; // Apple's routine.
|
||||
|
||||
// Dynamic, on demand connection?
|
||||
- (BOOL) isConnectionOnDemand;
|
||||
|
||||
// Is user intervention required?
|
||||
- (BOOL) isInterventionRequired;
|
||||
|
||||
// Routines for specific connection testing by your app.
|
||||
- (BOOL) isReachableViaWWAN;
|
||||
- (BOOL) isReachableViaWiFi;
|
||||
|
||||
- (SCNetworkReachabilityFlags) reachabilityFlags;
|
||||
|
||||
@end
|
|
@ -0,0 +1,814 @@
|
|||
/*
|
||||
|
||||
File: Reachability.m
|
||||
Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
|
||||
|
||||
Version: 2.0.4ddg
|
||||
*/
|
||||
|
||||
/*
|
||||
Significant additions made by Andrew W. Donoho, August 11, 2009.
|
||||
This is a derived work of Apple's Reachability v2.0 class.
|
||||
|
||||
The below license is the new BSD license with the OSI recommended personalizations.
|
||||
<http://www.opensource.org/licenses/bsd-license.php>
|
||||
|
||||
Extensions Copyright (C) 2009 Donoho Design Group, LLC. All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of Andrew W. Donoho nor Donoho Design Group, L.L.C.
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY DONOHO DESIGN GROUP, L.L.C. "AS IS" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Apple's Original License on Reachability v2.0
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and your
|
||||
use, installation, modification or redistribution of this Apple software
|
||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
||||
please do not use, install, modify or redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject
|
||||
to these terms, Apple grants you a personal, non-exclusive license, under
|
||||
Apple's copyrights in this original Apple software (the "Apple Software"), to
|
||||
use, reproduce, modify and redistribute the Apple Software, with or without
|
||||
modifications, in source and/or binary forms; provided that if you redistribute
|
||||
the Apple Software in its entirety and without modifications, you must retain
|
||||
this notice and the following text and disclaimers in all such redistributions
|
||||
of the Apple Software.
|
||||
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may be used
|
||||
to endorse or promote products derived from the Apple Software without specific
|
||||
prior written permission from Apple. Except as expressly stated in this notice,
|
||||
no other rights or licenses, express or implied, are granted by Apple herein,
|
||||
including but not limited to any patent rights that may be infringed by your
|
||||
derivative works or by other works in which the Apple Software may be
|
||||
incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||
COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
|
||||
DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
|
||||
CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Each reachability object now has a copy of the key used to store it in a dictionary.
|
||||
This allows each observer to quickly determine if the event is important to them.
|
||||
*/
|
||||
|
||||
#import <sys/socket.h>
|
||||
#import <netinet/in.h>
|
||||
#import <netinet6/in6.h>
|
||||
#import <arpa/inet.h>
|
||||
#import <ifaddrs.h>
|
||||
#import <netdb.h>
|
||||
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#import "Reachability.h"
|
||||
|
||||
NSString *const kInternetConnection = @"InternetConnection";
|
||||
NSString *const kLocalWiFiConnection = @"LocalWiFiConnection";
|
||||
NSString *const kReachabilityChangedNotification = @"NetworkReachabilityChangedNotification";
|
||||
|
||||
#define CLASS_DEBUG 1 // Turn on logReachabilityFlags. Must also have a project wide defined DEBUG.
|
||||
|
||||
#if (defined DEBUG && defined CLASS_DEBUG)
|
||||
#define logReachabilityFlags(flags) (logReachabilityFlags_(__PRETTY_FUNCTION__, __LINE__, flags))
|
||||
|
||||
static NSString *reachabilityFlags_(SCNetworkReachabilityFlags flags) {
|
||||
|
||||
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 30000) // Apple advises you to use the magic number instead of a symbol.
|
||||
return [NSString stringWithFormat:@"Reachability Flags: %c%c %c%c%c%c%c%c%c",
|
||||
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
|
||||
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-'];
|
||||
#else
|
||||
// Compile out the v3.0 features for v2.2.1 deployment.
|
||||
return [NSString stringWithFormat:@"Reachability Flags: %c%c %c%c%c%c%c%c",
|
||||
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
|
||||
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
|
||||
// v3 kSCNetworkReachabilityFlagsConnectionOnTraffic == v2 kSCNetworkReachabilityFlagsConnectionAutomatic
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionAutomatic) ? 'C' : '-',
|
||||
// (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', // No v2 equivalent.
|
||||
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-'];
|
||||
#endif
|
||||
|
||||
} // reachabilityFlags_()
|
||||
|
||||
static void logReachabilityFlags_(const char *name, int line, SCNetworkReachabilityFlags flags) {
|
||||
|
||||
NSLog(@"%s (%d) \n\t%@", name, line, reachabilityFlags_(flags));
|
||||
|
||||
} // logReachabilityFlags_()
|
||||
|
||||
#define logNetworkStatus(status) (logNetworkStatus_(__PRETTY_FUNCTION__, __LINE__, status))
|
||||
|
||||
static void logNetworkStatus_(const char *name, int line, NetworkStatus status) {
|
||||
|
||||
NSString *statusString = nil;
|
||||
|
||||
switch (status) {
|
||||
case kNotReachable:
|
||||
statusString = @"Not Reachable";
|
||||
break;
|
||||
case kReachableViaWWAN:
|
||||
statusString = @"Reachable via WWAN";
|
||||
break;
|
||||
case kReachableViaWiFi:
|
||||
statusString = @"Reachable via WiFi";
|
||||
break;
|
||||
}
|
||||
|
||||
NSLog(@"%s (%d) \n\tNetwork Status: %@", name, line, statusString);
|
||||
|
||||
} // logNetworkStatus_()
|
||||
|
||||
#else
|
||||
#define logReachabilityFlags(flags)
|
||||
#define logNetworkStatus(status)
|
||||
#endif
|
||||
|
||||
@interface Reachability (private)
|
||||
|
||||
- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags;
|
||||
|
||||
@end
|
||||
|
||||
@implementation Reachability
|
||||
|
||||
@synthesize key = key_;
|
||||
|
||||
// Preclude direct access to ivars.
|
||||
+ (BOOL) accessInstanceVariablesDirectly {
|
||||
|
||||
return NO;
|
||||
|
||||
} // accessInstanceVariablesDirectly
|
||||
|
||||
|
||||
- (void) dealloc {
|
||||
|
||||
[self stopNotifier];
|
||||
if(reachabilityRef) {
|
||||
|
||||
CFRelease(reachabilityRef); reachabilityRef = NULL;
|
||||
|
||||
}
|
||||
|
||||
self.key = nil;
|
||||
|
||||
[super dealloc];
|
||||
|
||||
} // dealloc
|
||||
|
||||
|
||||
- (Reachability *) initWithReachabilityRef: (SCNetworkReachabilityRef) ref
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
reachabilityRef = ref;
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
} // initWithReachabilityRef:
|
||||
|
||||
|
||||
#if (defined DEBUG && defined CLASS_DEBUG)
|
||||
- (NSString *) description {
|
||||
|
||||
NSAssert(reachabilityRef, @"-description called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
|
||||
SCNetworkReachabilityGetFlags(reachabilityRef, &flags);
|
||||
|
||||
return [NSString stringWithFormat: @"%@\n\t%@", self.key, reachabilityFlags_(flags)];
|
||||
|
||||
} // description
|
||||
#endif
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Notification Management Methods
|
||||
|
||||
|
||||
//Start listening for reachability notifications on the current run loop
|
||||
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) {
|
||||
|
||||
#pragma unused (target, flags)
|
||||
NSCAssert(info, @"info was NULL in ReachabilityCallback");
|
||||
NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was the wrong class in ReachabilityCallback");
|
||||
|
||||
//We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively
|
||||
// in case someone uses the Reachablity object in a different thread.
|
||||
NSAutoreleasePool* pool = [NSAutoreleasePool new];
|
||||
|
||||
// Post a notification to notify the client that the network reachability changed.
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification
|
||||
object: (Reachability *) info];
|
||||
|
||||
[pool release];
|
||||
|
||||
} // ReachabilityCallback()
|
||||
|
||||
|
||||
- (BOOL) startNotifier {
|
||||
|
||||
SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL};
|
||||
|
||||
if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context)) {
|
||||
|
||||
if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
|
||||
|
||||
return YES;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // startNotifier
|
||||
|
||||
|
||||
- (void) stopNotifier {
|
||||
|
||||
if(reachabilityRef) {
|
||||
|
||||
SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
|
||||
}
|
||||
|
||||
} // stopNotifier
|
||||
|
||||
|
||||
- (BOOL) isEqual: (Reachability *) r {
|
||||
|
||||
return [r.key isEqualToString: self.key];
|
||||
|
||||
} // isEqual:
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Reachability Allocation Methods
|
||||
|
||||
|
||||
+ (Reachability *) reachabilityWithHostName: (NSString *) hostName {
|
||||
|
||||
SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
|
||||
|
||||
if (ref) {
|
||||
|
||||
Reachability *r = [[[self alloc] initWithReachabilityRef: ref] autorelease];
|
||||
|
||||
r.key = hostName;
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
return nil;
|
||||
|
||||
} // reachabilityWithHostName
|
||||
|
||||
|
||||
+ (NSString *) makeAddressKey: (in_addr_t) addr {
|
||||
// addr is assumed to be in network byte order.
|
||||
|
||||
static const int highShift = 24;
|
||||
static const int highMidShift = 16;
|
||||
static const int lowMidShift = 8;
|
||||
static const in_addr_t mask = 0x000000ff;
|
||||
|
||||
addr = ntohl(addr);
|
||||
|
||||
return [NSString stringWithFormat: @"%d.%d.%d.%d",
|
||||
(addr >> highShift) & mask,
|
||||
(addr >> highMidShift) & mask,
|
||||
(addr >> lowMidShift) & mask,
|
||||
addr & mask];
|
||||
|
||||
} // makeAddressKey:
|
||||
|
||||
|
||||
+ (Reachability *) reachabilityWithAddress: (const struct sockaddr_in *) hostAddress {
|
||||
|
||||
SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
|
||||
|
||||
if (ref) {
|
||||
|
||||
Reachability *r = [[[self alloc] initWithReachabilityRef: ref] autorelease];
|
||||
|
||||
r.key = [self makeAddressKey: hostAddress->sin_addr.s_addr];
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
return nil;
|
||||
|
||||
} // reachabilityWithAddress
|
||||
|
||||
|
||||
+ (Reachability *) reachabilityForInternetConnection {
|
||||
|
||||
struct sockaddr_in zeroAddress;
|
||||
bzero(&zeroAddress, sizeof(zeroAddress));
|
||||
zeroAddress.sin_len = sizeof(zeroAddress);
|
||||
zeroAddress.sin_family = AF_INET;
|
||||
|
||||
Reachability *r = [self reachabilityWithAddress: &zeroAddress];
|
||||
|
||||
r.key = kInternetConnection;
|
||||
|
||||
return r;
|
||||
|
||||
} // reachabilityForInternetConnection
|
||||
|
||||
|
||||
+ (Reachability *) reachabilityForLocalWiFi {
|
||||
|
||||
struct sockaddr_in localWifiAddress;
|
||||
bzero(&localWifiAddress, sizeof(localWifiAddress));
|
||||
localWifiAddress.sin_len = sizeof(localWifiAddress);
|
||||
localWifiAddress.sin_family = AF_INET;
|
||||
// IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
|
||||
localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
|
||||
|
||||
Reachability *r = [self reachabilityWithAddress: &localWifiAddress];
|
||||
|
||||
r.key = kLocalWiFiConnection;
|
||||
|
||||
return r;
|
||||
|
||||
} // reachabilityForLocalWiFi
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Network Flag Handling Methods
|
||||
|
||||
|
||||
#if USE_DDG_EXTENSIONS
|
||||
//
|
||||
// iPhone condition codes as reported by a 3GS running iPhone OS v3.0.
|
||||
// Airplane Mode turned on: Reachability Flag Status: -- -------
|
||||
// WWAN Active: Reachability Flag Status: WR -t-----
|
||||
// WWAN Connection required: Reachability Flag Status: WR ct-----
|
||||
// WiFi turned on: Reachability Flag Status: -R ------- Reachable.
|
||||
// Local WiFi turned on: Reachability Flag Status: -R xxxxxxd Reachable.
|
||||
// WiFi turned on: Reachability Flag Status: -R ct----- Connection down. (Non-intuitive, empirically determined answer.)
|
||||
const SCNetworkReachabilityFlags kConnectionDown = kSCNetworkReachabilityFlagsConnectionRequired |
|
||||
kSCNetworkReachabilityFlagsTransientConnection;
|
||||
// WiFi turned on: Reachability Flag Status: -R ct-i--- Reachable but it will require user intervention (e.g. enter a WiFi password).
|
||||
// WiFi turned on: Reachability Flag Status: -R -t----- Reachable via VPN.
|
||||
//
|
||||
// In the below method, an 'x' in the flag status means I don't care about its value.
|
||||
//
|
||||
// This method differs from Apple's by testing explicitly for empirically observed values.
|
||||
// This gives me more confidence in it's correct behavior. Apple's code covers more cases
|
||||
// than mine. My code covers the cases that occur.
|
||||
//
|
||||
- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags {
|
||||
|
||||
if (flags & kSCNetworkReachabilityFlagsReachable) {
|
||||
|
||||
// Local WiFi -- Test derived from Apple's code: -localWiFiStatusForFlags:.
|
||||
if (self.key == kLocalWiFiConnection) {
|
||||
|
||||
// Reachability Flag Status: xR xxxxxxd Reachable.
|
||||
return (flags & kSCNetworkReachabilityFlagsIsDirect) ? kReachableViaWiFi : kNotReachable;
|
||||
|
||||
}
|
||||
|
||||
// Observed WWAN Values:
|
||||
// WWAN Active: Reachability Flag Status: WR -t-----
|
||||
// WWAN Connection required: Reachability Flag Status: WR ct-----
|
||||
//
|
||||
// Test Value: Reachability Flag Status: WR xxxxxxx
|
||||
if (flags & kSCNetworkReachabilityFlagsIsWWAN) { return kReachableViaWWAN; }
|
||||
|
||||
// Clear moot bits.
|
||||
flags &= ~kSCNetworkReachabilityFlagsReachable;
|
||||
flags &= ~kSCNetworkReachabilityFlagsIsDirect;
|
||||
flags &= ~kSCNetworkReachabilityFlagsIsLocalAddress; // kInternetConnection is local.
|
||||
|
||||
// Reachability Flag Status: -R ct---xx Connection down.
|
||||
if (flags == kConnectionDown) { return kNotReachable; }
|
||||
|
||||
// Reachability Flag Status: -R -t---xx Reachable. WiFi + VPN(is up) (Thank you Ling Wang)
|
||||
if (flags & kSCNetworkReachabilityFlagsTransientConnection) { return kReachableViaWiFi; }
|
||||
|
||||
// Reachability Flag Status: -R -----xx Reachable.
|
||||
if (flags == 0) { return kReachableViaWiFi; }
|
||||
|
||||
// Apple's code tests for dynamic connection types here. I don't.
|
||||
// If a connection is required, regardless of whether it is on demand or not, it is a WiFi connection.
|
||||
// If you care whether a connection needs to be brought up, use -isConnectionRequired.
|
||||
// If you care about whether user intervention is necessary, use -isInterventionRequired.
|
||||
// If you care about dynamically establishing the connection, use -isConnectionIsOnDemand.
|
||||
|
||||
// Reachability Flag Status: -R cxxxxxx Reachable.
|
||||
if (flags & kSCNetworkReachabilityFlagsConnectionRequired) { return kReachableViaWiFi; }
|
||||
|
||||
// Required by the compiler. Should never get here. Default to not connected.
|
||||
#if (defined DEBUG && defined CLASS_DEBUG)
|
||||
NSAssert1(NO, @"Uncaught reachability test. Flags: %@", reachabilityFlags_(flags));
|
||||
#endif
|
||||
return kNotReachable;
|
||||
|
||||
}
|
||||
|
||||
// Reachability Flag Status: x- xxxxxxx
|
||||
return kNotReachable;
|
||||
|
||||
} // networkStatusForFlags:
|
||||
|
||||
|
||||
- (NetworkStatus) currentReachabilityStatus {
|
||||
|
||||
NSAssert(reachabilityRef, @"currentReachabilityStatus called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
NetworkStatus status = kNotReachable;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
// logReachabilityFlags(flags);
|
||||
|
||||
status = [self networkStatusForFlags: flags];
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
return kNotReachable;
|
||||
|
||||
} // currentReachabilityStatus
|
||||
|
||||
|
||||
- (BOOL) isReachable {
|
||||
|
||||
NSAssert(reachabilityRef, @"isReachable called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
NetworkStatus status = kNotReachable;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
// logReachabilityFlags(flags);
|
||||
|
||||
status = [self networkStatusForFlags: flags];
|
||||
|
||||
// logNetworkStatus(status);
|
||||
|
||||
return (kNotReachable != status);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isReachable
|
||||
|
||||
|
||||
- (BOOL) isConnectionRequired {
|
||||
|
||||
NSAssert(reachabilityRef, @"isConnectionRequired called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isConnectionRequired
|
||||
|
||||
|
||||
- (BOOL) connectionRequired {
|
||||
|
||||
return [self isConnectionRequired];
|
||||
|
||||
} // connectionRequired
|
||||
#endif
|
||||
|
||||
|
||||
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 30000)
|
||||
static const SCNetworkReachabilityFlags kOnDemandConnection = kSCNetworkReachabilityFlagsConnectionOnTraffic |
|
||||
kSCNetworkReachabilityFlagsConnectionOnDemand;
|
||||
#else
|
||||
static const SCNetworkReachabilityFlags kOnDemandConnection = kSCNetworkReachabilityFlagsConnectionAutomatic;
|
||||
#endif
|
||||
|
||||
- (BOOL) isConnectionOnDemand {
|
||||
|
||||
NSAssert(reachabilityRef, @"isConnectionIsOnDemand called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
|
||||
(flags & kOnDemandConnection));
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isConnectionOnDemand
|
||||
|
||||
|
||||
- (BOOL) isInterventionRequired {
|
||||
|
||||
NSAssert(reachabilityRef, @"isInterventionRequired called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
|
||||
(flags & kSCNetworkReachabilityFlagsInterventionRequired));
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isInterventionRequired
|
||||
|
||||
|
||||
- (BOOL) isReachableViaWWAN {
|
||||
|
||||
NSAssert(reachabilityRef, @"isReachableViaWWAN called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
NetworkStatus status = kNotReachable;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
status = [self networkStatusForFlags: flags];
|
||||
|
||||
return (kReachableViaWWAN == status);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isReachableViaWWAN
|
||||
|
||||
|
||||
- (BOOL) isReachableViaWiFi {
|
||||
|
||||
NSAssert(reachabilityRef, @"isReachableViaWiFi called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
NetworkStatus status = kNotReachable;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
status = [self networkStatusForFlags: flags];
|
||||
|
||||
return (kReachableViaWiFi == status);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isReachableViaWiFi
|
||||
|
||||
|
||||
- (SCNetworkReachabilityFlags) reachabilityFlags {
|
||||
|
||||
NSAssert(reachabilityRef, @"reachabilityFlags called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
return flags;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
} // reachabilityFlags
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Apple's Network Flag Handling Methods
|
||||
|
||||
|
||||
#if !USE_DDG_EXTENSIONS
|
||||
/*
|
||||
*
|
||||
* Apple's Network Status testing code.
|
||||
* The only changes that have been made are to use the new logReachabilityFlags macro and
|
||||
* test for local WiFi via the key instead of Apple's boolean. Also, Apple's code was for v3.0 only
|
||||
* iPhone OS. v2.2.1 and earlier conditional compiling is turned on. Hence, to mirror Apple's behavior,
|
||||
* set your Base SDK to v3.0 or higher.
|
||||
*
|
||||
*/
|
||||
|
||||
- (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags
|
||||
{
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
BOOL retVal = NotReachable;
|
||||
if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))
|
||||
{
|
||||
retVal = ReachableViaWiFi;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags
|
||||
{
|
||||
logReachabilityFlags(flags);
|
||||
if (!(flags & kSCNetworkReachabilityFlagsReachable))
|
||||
{
|
||||
// if target host is not reachable
|
||||
return NotReachable;
|
||||
}
|
||||
|
||||
BOOL retVal = NotReachable;
|
||||
|
||||
if (!(flags & kSCNetworkReachabilityFlagsConnectionRequired))
|
||||
{
|
||||
// if target host is reachable and no connection is required
|
||||
// then we'll assume (for now) that your on Wi-Fi
|
||||
retVal = ReachableViaWiFi;
|
||||
}
|
||||
|
||||
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 30000) // Apple advises you to use the magic number instead of a symbol.
|
||||
if ((flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ||
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic))
|
||||
#else
|
||||
if (flags & kSCNetworkReachabilityFlagsConnectionAutomatic)
|
||||
#endif
|
||||
{
|
||||
// ... and the connection is on-demand (or on-traffic) if the
|
||||
// calling application is using the CFSocketStream or higher APIs
|
||||
|
||||
if (!(flags & kSCNetworkReachabilityFlagsInterventionRequired))
|
||||
{
|
||||
// ... and no [user] intervention is needed
|
||||
retVal = ReachableViaWiFi;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & kSCNetworkReachabilityFlagsIsWWAN)
|
||||
{
|
||||
// ... but WWAN connections are OK if the calling application
|
||||
// is using the CFNetwork (CFSocketStream?) APIs.
|
||||
retVal = ReachableViaWWAN;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
- (NetworkStatus) currentReachabilityStatus
|
||||
{
|
||||
NSAssert(reachabilityRef, @"currentReachabilityStatus called with NULL reachabilityRef");
|
||||
|
||||
NetworkStatus retVal = NotReachable;
|
||||
SCNetworkReachabilityFlags flags;
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
|
||||
{
|
||||
if(self.key == kLocalWiFiConnection)
|
||||
{
|
||||
retVal = [self localWiFiStatusForFlags: flags];
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = [self networkStatusForFlags: flags];
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) isReachable {
|
||||
|
||||
NSAssert(reachabilityRef, @"isReachable called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
NetworkStatus status = kNotReachable;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
if(self.key == kLocalWiFiConnection) {
|
||||
|
||||
status = [self localWiFiStatusForFlags: flags];
|
||||
|
||||
} else {
|
||||
|
||||
status = [self networkStatusForFlags: flags];
|
||||
|
||||
}
|
||||
|
||||
return (kNotReachable != status);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isReachable
|
||||
|
||||
|
||||
- (BOOL) isConnectionRequired {
|
||||
|
||||
return [self connectionRequired];
|
||||
|
||||
} // isConnectionRequired
|
||||
|
||||
|
||||
- (BOOL) connectionRequired {
|
||||
|
||||
NSAssert(reachabilityRef, @"connectionRequired called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // connectionRequired
|
||||
#endif
|
||||
|
||||
@end
|
|
@ -7,6 +7,10 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
2BCF880C1793A26A006FC859 /* MBProgressHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BCF880B1793A26A006FC859 /* MBProgressHUD.m */; };
|
||||
2BCF88101793ABA0006FC859 /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BCF880F1793ABA0006FC859 /* Reachability.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
2BCF88121793CB4F006FC859 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2BCF88111793CB4F006FC859 /* CFNetwork.framework */; };
|
||||
2BCF88141793CB94006FC859 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2BCF88131793CB94006FC859 /* SystemConfiguration.framework */; };
|
||||
D5DB805A1792F2BF0081662A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5DB80591792F2BF0081662A /* UIKit.framework */; };
|
||||
D5DB805C1792F2BF0081662A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5DB805B1792F2BF0081662A /* Foundation.framework */; };
|
||||
D5DB805E1792F2BF0081662A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5DB805D1792F2BF0081662A /* CoreGraphics.framework */; };
|
||||
|
@ -42,6 +46,12 @@
|
|||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
2BCF880A1793A26A006FC859 /* MBProgressHUD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBProgressHUD.h; sourceTree = "<group>"; };
|
||||
2BCF880B1793A26A006FC859 /* MBProgressHUD.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBProgressHUD.m; sourceTree = "<group>"; };
|
||||
2BCF880E1793ABA0006FC859 /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = "<group>"; };
|
||||
2BCF880F1793ABA0006FC859 /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = "<group>"; };
|
||||
2BCF88111793CB4F006FC859 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
|
||||
2BCF88131793CB94006FC859 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
|
||||
D5DB80561792F2BF0081662A /* RedmineMobile.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RedmineMobile.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D5DB80591792F2BF0081662A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||
D5DB805B1792F2BF0081662A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
|
@ -106,6 +116,8 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2BCF88141793CB94006FC859 /* SystemConfiguration.framework in Frameworks */,
|
||||
2BCF88121793CB4F006FC859 /* CFNetwork.framework in Frameworks */,
|
||||
D5DB805A1792F2BF0081662A /* UIKit.framework in Frameworks */,
|
||||
D5DB805C1792F2BF0081662A /* Foundation.framework in Frameworks */,
|
||||
D5DB805E1792F2BF0081662A /* CoreGraphics.framework in Frameworks */,
|
||||
|
@ -115,6 +127,24 @@
|
|||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
2BCF88091793A26A006FC859 /* MBProgressHUD */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2BCF880A1793A26A006FC859 /* MBProgressHUD.h */,
|
||||
2BCF880B1793A26A006FC859 /* MBProgressHUD.m */,
|
||||
);
|
||||
path = MBProgressHUD;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2BCF880D1793ABA0006FC859 /* Reachability */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2BCF880E1793ABA0006FC859 /* Reachability.h */,
|
||||
2BCF880F1793ABA0006FC859 /* Reachability.m */,
|
||||
);
|
||||
path = Reachability;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D5DB804D1792F2BF0081662A = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -136,6 +166,8 @@
|
|||
D5DB80581792F2BF0081662A /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2BCF88131793CB94006FC859 /* SystemConfiguration.framework */,
|
||||
2BCF88111793CB4F006FC859 /* CFNetwork.framework */,
|
||||
D5DB80591792F2BF0081662A /* UIKit.framework */,
|
||||
D5DB805B1792F2BF0081662A /* Foundation.framework */,
|
||||
D5DB805D1792F2BF0081662A /* CoreGraphics.framework */,
|
||||
|
@ -173,6 +205,8 @@
|
|||
D5DB80761792F3EE0081662A /* Libs */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2BCF880D1793ABA0006FC859 /* Reachability */,
|
||||
2BCF88091793A26A006FC859 /* MBProgressHUD */,
|
||||
D5DB80771792F3EE0081662A /* AFNetworking */,
|
||||
D5DB808B1792F3EE0081662A /* iOSPlot */,
|
||||
D5DB80901792F3EE0081662A /* JSONKit */,
|
||||
|
@ -365,6 +399,8 @@
|
|||
D5DB80BA17930C830081662A /* OZLNetworkBase.m in Sources */,
|
||||
D5DB80BD17930ECD0081662A /* OZLSingleton.m in Sources */,
|
||||
D5DB80C217931C8B0081662A /* OZLModelProject.m in Sources */,
|
||||
2BCF880C1793A26A006FC859 /* MBProgressHUD.m in Sources */,
|
||||
2BCF88101793ABA0006FC859 /* Reachability.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -483,6 +519,7 @@
|
|||
D5DB80751792F2BF0081662A /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
[self changeSideViewOffset:90];
|
||||
[self changeSideViewOffset:40];
|
||||
|
||||
UIBarButtonItem* projectListBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemBookmarks target:self action:@selector(showLeft)];
|
||||
[self.navigationItem setLeftBarButtonItem:projectListBtn];
|
||||
|
|
|
@ -12,10 +12,11 @@
|
|||
#import "OZLAccountViewController.h"
|
||||
#import "OZLNetwork.h"
|
||||
#import "OZLModelProject.h"
|
||||
#import "MBProgressHUD.h"
|
||||
|
||||
@interface OZLProjectListViewController (){
|
||||
NSMutableArray* _projectList;
|
||||
|
||||
MBProgressHUD * _HUD;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -37,15 +38,21 @@
|
|||
_projectsTableview.delegate = self;
|
||||
_projectsTableview.dataSource = self;
|
||||
|
||||
_HUD = [[MBProgressHUD alloc] initWithView:self.view];
|
||||
[self.view addSubview:_HUD];
|
||||
_HUD.labelText = @"Refreshing...";
|
||||
}
|
||||
|
||||
-(void) viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[_HUD show:YES];
|
||||
|
||||
// refresh project list
|
||||
[OZLNetwork getProjectListWithParams:nil andBlock:^(NSArray *result, NSError *error) {
|
||||
NSLog(@"respond:%@",result.description);
|
||||
_projectList = [[NSMutableArray alloc] initWithArray: result];
|
||||
[_projectsTableview reloadData];
|
||||
[_HUD hide:YES];
|
||||
}];
|
||||
}
|
||||
- (void)didReceiveMemoryWarning
|
||||
|
@ -80,14 +87,14 @@
|
|||
{
|
||||
|
||||
// Return the number of sections.
|
||||
return [_projectList count];
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
|
||||
// Return the number of rows in the section.
|
||||
return 1;
|
||||
return [_projectList count];
|
||||
}
|
||||
|
||||
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
|
@ -97,7 +104,7 @@
|
|||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
NSString* cellidentifier = [NSString stringWithFormat:@"project_cell_id_%d",indexPath.row];
|
||||
NSString* cellidentifier = [NSString stringWithFormat:@"project_cell_id"];
|
||||
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:cellidentifier];
|
||||
if (!cell) {
|
||||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellidentifier];
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
[self changeSideViewOffset:90];
|
||||
[self changeSideViewOffset:40];
|
||||
|
||||
UIBarButtonItem* projectListBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemOrganize target:self action:@selector(showLeft)];
|
||||
[self.navigationItem setLeftBarButtonItem:projectListBtn];
|
||||
|
|
Loading…
Reference in New Issue