diff --git a/RedmineMobile/Libs/MBProgressHUD/LICENSE.txt b/RedmineMobile/Libs/MBProgressHUD/LICENSE.txt new file mode 100755 index 0000000..c51b6b0 --- /dev/null +++ b/RedmineMobile/Libs/MBProgressHUD/LICENSE.txt @@ -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. \ No newline at end of file diff --git a/RedmineMobile/Libs/MBProgressHUD/MBProgressHUD.h b/RedmineMobile/Libs/MBProgressHUD/MBProgressHUD.h new file mode 100755 index 0000000..a1d6935 --- /dev/null +++ b/RedmineMobile/Libs/MBProgressHUD/MBProgressHUD.h @@ -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 +#import +#import + +@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 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 + +@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 diff --git a/RedmineMobile/Libs/MBProgressHUD/MBProgressHUD.m b/RedmineMobile/Libs/MBProgressHUD/MBProgressHUD.m new file mode 100755 index 0000000..34f2fb7 --- /dev/null +++ b/RedmineMobile/Libs/MBProgressHUD/MBProgressHUD.m @@ -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 diff --git a/RedmineMobile/Libs/Reachability/Reachability.h b/RedmineMobile/Libs/Reachability/Reachability.h new file mode 100644 index 0000000..78657d6 --- /dev/null +++ b/RedmineMobile/Libs/Reachability/Reachability.h @@ -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. + + + 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 +#import +#import + +#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 diff --git a/RedmineMobile/Libs/Reachability/Reachability.m b/RedmineMobile/Libs/Reachability/Reachability.m new file mode 100644 index 0000000..a8e3cc2 --- /dev/null +++ b/RedmineMobile/Libs/Reachability/Reachability.m @@ -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. + + + 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 +#import +#import +#import +#import +#import + +#import + +#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 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 diff --git a/RedmineMobile/RedmineMobile.xcodeproj/project.pbxproj b/RedmineMobile/RedmineMobile.xcodeproj/project.pbxproj index fd2747f..cbfc3a3 100644 --- a/RedmineMobile/RedmineMobile.xcodeproj/project.pbxproj +++ b/RedmineMobile/RedmineMobile.xcodeproj/project.pbxproj @@ -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 = ""; }; + 2BCF880B1793A26A006FC859 /* MBProgressHUD.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBProgressHUD.m; sourceTree = ""; }; + 2BCF880E1793ABA0006FC859 /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = ""; }; + 2BCF880F1793ABA0006FC859 /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = ""; }; + 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 = ""; + }; + 2BCF880D1793ABA0006FC859 /* Reachability */ = { + isa = PBXGroup; + children = ( + 2BCF880E1793ABA0006FC859 /* Reachability.h */, + 2BCF880F1793ABA0006FC859 /* Reachability.m */, + ); + path = Reachability; + sourceTree = ""; + }; 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 */ }; diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLAccountViewController.m b/RedmineMobile/RedmineMobile/ViewControllers/OZLAccountViewController.m index 110ec30..bb65526 100644 --- a/RedmineMobile/RedmineMobile/ViewControllers/OZLAccountViewController.m +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLAccountViewController.m @@ -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]; diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectListViewController.m b/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectListViewController.m index e552295..77837d7 100644 --- a/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectListViewController.m +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectListViewController.m @@ -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]; diff --git a/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.m b/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.m index 92daac2..4a06ff0 100644 --- a/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.m +++ b/RedmineMobile/RedmineMobile/ViewControllers/OZLProjectViewController.m @@ -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];