Browse Source

new system notification error for low interest

Marino Faggiana 7 years ago
parent
commit
9d45b8c1ef

+ 169 - 0
Libraries external/JDStatusBarNotification/JDStatusBarNotification.h

@@ -0,0 +1,169 @@
+//
+//  JDStatusBarNotification.h
+//
+//  Based on KGStatusBar by Kevin Gibbon
+//
+//  Created by Markus Emrich on 10/28/13.
+//  Copyright 2013 Markus Emrich. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+#import "JDStatusBarStyle.h"
+#import "JDStatusBarView.h"
+
+/**
+ *  A block that is used to define the appearance of a notification.
+ *  A JDStatusBarStyle instance defines the notification appeareance.
+ *
+ *  @param style The current default JDStatusBarStyle instance.
+ *
+ *  @return The modified JDStatusBarStyle instance.
+ */
+typedef JDStatusBarStyle*(^JDPrepareStyleBlock)(JDStatusBarStyle *style);
+
+/**
+ *  This class is a singletion which is used to present notifications
+ *  on top of the status bar. To present a notification, use one of the
+ *  given class methods.
+ */
+@interface JDStatusBarNotification : NSObject
+
+#pragma mark Presentation
+
+/**
+ *  Show a notification. It won't hide automatically,
+ *  you have to dimiss it on your own.
+ *
+ *  @param status The message to display
+ *
+ *  @return The presented notification view for further customization
+ */
++ (JDStatusBarView*)showWithStatus:(NSString *)status;
+
+/**
+ *  Show a notification with a specific style. It won't
+ *  hide automatically, you have to dimiss it on your own.
+ *
+ *  @param status The message to display
+ *  @param styleName The name of the style. You can use any JDStatusBarStyle constant
+ *  (JDStatusBarStyleDefault, etc.), or a custom style identifier, after you added a
+ *  custom style. If this is nil, the default style will be used.
+ *
+ *  @return The presented notification view for further customization
+ */
++ (JDStatusBarView*)showWithStatus:(NSString *)status
+                         styleName:(NSString*)styleName;
+
+/**
+ *  Same as showWithStatus:, but the notification will
+ *  automatically dismiss after the given timeInterval.
+ *
+ *  @param status       The message to display
+ *  @param timeInterval The duration, how long the notification
+ *  is displayed. (Including the animation duration)
+ *
+ *  @return The presented notification view for further customization
+ */
++ (JDStatusBarView*)showWithStatus:(NSString *)status
+                      dismissAfter:(NSTimeInterval)timeInterval;
+
+/**
+ *  Same as showWithStatus:styleName:, but the notification
+ *  will automatically dismiss after the given timeInterval.
+ *
+ *  @param status       The message to display
+ *  @param timeInterval The duration, how long the notification
+ *  is displayed. (Including the animation duration)
+ *  @param styleName The name of the style. You can use any JDStatusBarStyle constant
+ *  (JDStatusBarStyleDefault, etc.), or a custom style identifier, after you added a
+ *  custom style. If this is nil, the default style will be used.
+ *
+ *  @return The presented notification view for further customization
+ */
++ (JDStatusBarView*)showWithStatus:(NSString *)status
+                      dismissAfter:(NSTimeInterval)timeInterval
+                         styleName:(NSString*)styleName;
+
+#pragma mark Dismissal
+
+/**
+ *  Calls dismissAnimated: with animated set to YES
+ */
++ (void)dismiss;
+
+/**
+ *  Dismisses any currently displayed notification immediately
+ *
+ *  @param animated If this is YES, the animation style used
+ *  for presentation will also be used for the dismissal.
+ */
++ (void)dismissAnimated:(BOOL)animated;
+
+/**
+ *  Same as dismissAnimated:, but you can specify a delay,
+ *  so the notification wont be dismissed immediately
+ *
+ *  @param delay The delay, how long the notification should stay visible
+ */
++ (void)dismissAfter:(NSTimeInterval)delay;
+
+#pragma mark Styles
+
+/**
+ *  This changes the default style, which is always used
+ *  when a method without styleName is used for presentation, or
+ *  styleName is nil, or no style is found with this name.
+ *
+ *  @param prepareBlock A block, which has a JDStatusBarStyle instance as
+ *  parameter. This instance can be modified to suit your needs. You need
+ *  to return the modified style again.
+ */
++ (void)setDefaultStyle:(JDPrepareStyleBlock)prepareBlock;
+
+/**
+ *  Adds a custom style, which than can be used
+ *  in the presentation methods.
+ *
+ *  @param identifier   The identifier, which will
+ *  later be used to reference the configured style.
+ *  @param prepareBlock A block, which has a JDStatusBarStyle instance as
+ *  parameter. This instance can be modified to suit your needs. You need
+ *  to return the modified style again.
+ *
+ *  @return Returns the given identifier, so it can
+ *  be directly used as styleName parameter.
+ */
++ (NSString*)addStyleNamed:(NSString*)identifier
+                   prepare:(JDPrepareStyleBlock)prepareBlock;
+
+#pragma mark progress & activity
+
+/**
+ *  Show the progress below the label.
+ *
+ *  @param progress Relative progress from 0.0 to 1.0
+ */
++ (void)showProgress:(CGFloat)progress;
+
+/**
+ *  Shows an activity indicator in front of the notification text
+ *
+ *  @param show  Use this flag to show or hide the activity indicator
+ *  @param style Sets the style of the activity indicator
+ */
++ (void)showActivityIndicator:(BOOL)show
+               indicatorStyle:(UIActivityIndicatorViewStyle)style;
+
+#pragma mark state
+
+/**
+ *  This method tests, if a notification is currently displayed.
+ *
+ *  @return YES, if a notification is currently displayed. Otherwise NO.
+ */
++ (BOOL)isVisible;
+
+@end
+
+

+ 600 - 0
Libraries external/JDStatusBarNotification/JDStatusBarNotification.m

@@ -0,0 +1,600 @@
+//
+//  JDStatusBarNotification.m
+//
+//  Based on KGStatusBar by Kevin Gibbon
+//
+//  Created by Markus Emrich on 10/28/13.
+//  Copyright 2013 Markus Emrich. All rights reserved.
+//
+
+#import <QuartzCore/QuartzCore.h>
+
+#import "JDStatusBarNotification.h"
+
+@interface JDStatusBarStyle (Hidden)
++ (NSArray*)allDefaultStyleIdentifier;
++ (JDStatusBarStyle*)defaultStyleWithName:(NSString*)styleName;
+@end
+
+@interface JDStatusBarNotificationViewController : UIViewController
+@end
+
+@interface UIApplication (mainWindow)
+- (UIWindow*)mainApplicationWindowIgnoringWindow:(UIWindow*)ignoringWindow;
+@end
+
+@interface JDStatusBarNotification () <CAAnimationDelegate>
+@property (nonatomic, strong, readonly) UIWindow *overlayWindow;
+@property (nonatomic, strong, readonly) UIView *progressView;
+@property (nonatomic, strong, readonly) JDStatusBarView *topBar;
+
+@property (nonatomic, strong) NSTimer *dismissTimer;
+@property (nonatomic, assign) CGFloat progress;
+
+@property (nonatomic, weak) JDStatusBarStyle *activeStyle;
+@property (nonatomic, strong) JDStatusBarStyle *defaultStyle;
+@property (nonatomic, strong) NSMutableDictionary *userStyles;
+@end
+
+@implementation JDStatusBarNotification
+
+@synthesize overlayWindow = _overlayWindow;
+@synthesize progressView = _progressView;
+@synthesize topBar = _topBar;
+
+#pragma mark Class methods
+
++ (JDStatusBarNotification*)sharedInstance {
+  static dispatch_once_t once;
+  static JDStatusBarNotification *sharedInstance;
+  dispatch_once(&once, ^ {
+    sharedInstance = [[self alloc] init];
+  });
+  return sharedInstance;
+}
+
++ (UIView*)showWithStatus:(NSString *)status;
+{
+  return [[self sharedInstance] showWithStatus:status
+                                     styleName:nil];
+}
+
++ (UIView*)showWithStatus:(NSString *)status
+                styleName:(NSString*)styleName;
+{
+  return [[self sharedInstance] showWithStatus:status
+                                     styleName:styleName];
+}
+
++ (UIView*)showWithStatus:(NSString *)status
+             dismissAfter:(NSTimeInterval)timeInterval;
+{
+  UIView *view = [[self sharedInstance] showWithStatus:status
+                                             styleName:nil];
+  [self dismissAfter:timeInterval];
+  return view;
+}
+
++ (UIView*)showWithStatus:(NSString *)status
+             dismissAfter:(NSTimeInterval)timeInterval
+                styleName:(NSString*)styleName;
+{
+  UIView *view = [[self sharedInstance] showWithStatus:status
+                                             styleName:styleName];
+  [self dismissAfter:timeInterval];
+  return view;
+}
+
++ (void)dismiss;
+{
+  [self dismissAnimated:YES];
+}
+
++ (void)dismissAnimated:(BOOL)animated;
+{
+  [[self sharedInstance] dismissAnimated:animated];
+}
+
++ (void)dismissAfter:(NSTimeInterval)delay;
+{
+  [[self sharedInstance] setDismissTimerWithInterval:delay];
+}
+
++ (void)setDefaultStyle:(JDPrepareStyleBlock)prepareBlock;
+{
+  NSAssert(prepareBlock != nil, @"No prepareBlock provided");
+
+  JDStatusBarStyle *style = [[self sharedInstance].defaultStyle copy];
+  [self sharedInstance].defaultStyle = prepareBlock(style);
+}
+
++ (NSString*)addStyleNamed:(NSString*)identifier
+                   prepare:(JDPrepareStyleBlock)prepareBlock;
+{
+  return [[self sharedInstance] addStyleNamed:identifier
+                                      prepare:prepareBlock];
+}
+
++ (void)showProgress:(CGFloat)progress;
+{
+  [[self sharedInstance] setProgress:progress];
+}
+
++ (void)showActivityIndicator:(BOOL)show indicatorStyle:(UIActivityIndicatorViewStyle)style;
+{
+  [[self sharedInstance] showActivityIndicator:show indicatorStyle:style];
+}
+
++ (BOOL)isVisible;
+{
+  return [[self sharedInstance] isVisible];
+}
+
+#pragma mark Implementation
+
+- (id)init
+{
+  if ((self = [super init]))
+  {
+    // set defaults
+    [self setupDefaultStyles];
+
+    // register for orientation changes
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willChangeStatusBarFrame:)
+                                                 name:UIApplicationWillChangeStatusBarFrameNotification object:nil];
+  }
+  return self;
+}
+
+- (void)dealloc
+{
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+#pragma mark Custom styles
+
+- (void)setupDefaultStyles;
+{
+  self.defaultStyle = [JDStatusBarStyle defaultStyleWithName:JDStatusBarStyleDefault];
+
+  self.userStyles = [NSMutableDictionary dictionary];
+  for (NSString *styleName in [JDStatusBarStyle allDefaultStyleIdentifier]) {
+    [self.userStyles setObject:[JDStatusBarStyle defaultStyleWithName:styleName] forKey:styleName];
+  }
+}
+
+- (NSString*)addStyleNamed:(NSString*)identifier
+                   prepare:(JDPrepareStyleBlock)prepareBlock;
+{
+  NSAssert(identifier != nil, @"No identifier provided");
+  NSAssert(prepareBlock != nil, @"No prepareBlock provided");
+
+  JDStatusBarStyle *style = [self.defaultStyle copy];
+  [self.userStyles setObject:prepareBlock(style) forKey:identifier];
+  return identifier;
+}
+
+#pragma mark Presentation
+
+- (UIView*)showWithStatus:(NSString *)status
+                styleName:(NSString*)styleName;
+{
+  JDStatusBarStyle *style = nil;
+  if (styleName != nil) {
+    style = self.userStyles[styleName];
+  }
+
+  if (style == nil) style = self.defaultStyle;
+  return [self showWithStatus:status style:style];
+}
+
+- (UIView*)showWithStatus:(NSString *)status
+                    style:(JDStatusBarStyle*)style;
+{
+  // first, check if status bar is visible at all
+  if ([UIApplication sharedApplication].statusBarHidden) return nil;
+
+  // prepare for new style
+  if (style != self.activeStyle) {
+    self.activeStyle = style;
+    if (self.activeStyle.animationType == JDStatusBarAnimationTypeFade) {
+      self.topBar.alpha = 0.0;
+      self.topBar.transform = CGAffineTransformIdentity;
+    } else {
+      self.topBar.alpha = 1.0;
+      self.topBar.transform = CGAffineTransformMakeTranslation(0, -self.topBar.frame.size.height);
+    }
+  }
+
+  // cancel previous dismissing & remove animations
+  [[NSRunLoop currentRunLoop] cancelPerformSelector:@selector(dismiss) target:self argument:nil];
+  [self.topBar.layer removeAllAnimations];
+
+  // create & show window
+  [self.overlayWindow setHidden:NO];
+
+  // update style
+  self.topBar.backgroundColor = style.barColor;
+  self.topBar.textVerticalPositionAdjustment = style.textVerticalPositionAdjustment;
+  UILabel *textLabel = self.topBar.textLabel;
+  textLabel.textColor = style.textColor;
+  textLabel.font = style.font;
+  textLabel.accessibilityLabel = status;
+  textLabel.text = status;
+
+  if (style.textShadow) {
+    textLabel.shadowColor = style.textShadow.shadowColor;
+    textLabel.shadowOffset = style.textShadow.shadowOffset;
+  } else {
+    textLabel.shadowColor = nil;
+    textLabel.shadowOffset = CGSizeZero;
+  }
+
+  // reset progress & activity
+  self.progress = 0.0;
+  [self showActivityIndicator:NO indicatorStyle:0];
+
+  // animate in
+  BOOL animationsEnabled = (style.animationType != JDStatusBarAnimationTypeNone);
+  if (animationsEnabled && style.animationType == JDStatusBarAnimationTypeBounce) {
+    [self animateInWithBounceAnimation];
+  } else {
+    [UIView animateWithDuration:(animationsEnabled ? 0.4 : 0.0) animations:^{
+      self.topBar.alpha = 1.0;
+      self.topBar.transform = CGAffineTransformIdentity;
+    }];
+  }
+
+  return self.topBar;
+}
+
+#pragma mark Dismissal
+
+- (void)setDismissTimerWithInterval:(NSTimeInterval)interval;
+{
+  [self.dismissTimer invalidate];
+  self.dismissTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:interval]
+                                               interval:0 target:self selector:@selector(dismiss:) userInfo:nil repeats:NO];
+  [[NSRunLoop currentRunLoop] addTimer:self.dismissTimer forMode:NSRunLoopCommonModes];
+}
+
+- (void)dismiss:(NSTimer*)timer;
+{
+  [self dismissAnimated:YES];
+}
+
+- (void)dismissAnimated:(BOOL)animated;
+{
+  [self.dismissTimer invalidate];
+  self.dismissTimer = nil;
+
+  // check animation type
+  BOOL animationsEnabled = (self.activeStyle.animationType != JDStatusBarAnimationTypeNone);
+  animated &= animationsEnabled;
+
+  dispatch_block_t animation = ^{
+    if (self.activeStyle.animationType == JDStatusBarAnimationTypeFade) {
+      self.topBar.alpha = 0.0;
+    } else {
+      self.topBar.transform = CGAffineTransformMakeTranslation(0, -self.topBar.frame.size.height);
+    }
+  };
+
+  void(^complete)(BOOL) = ^(BOOL finished) {
+    [self.overlayWindow removeFromSuperview];
+    [self.overlayWindow setHidden:YES];
+    _overlayWindow.rootViewController = nil;
+    _overlayWindow = nil;
+    _progressView = nil;
+    _topBar = nil;
+  };
+
+  if (animated) {
+    // animate out
+    [UIView animateWithDuration:0.4 animations:animation completion:complete];
+  } else {
+    animation();
+    complete(YES);
+  }
+}
+
+#pragma mark Bounce Animation
+
+- (void)animateInWithBounceAnimation;
+{
+  //don't animate in, if topBar is already fully visible
+  if (self.topBar.frame.origin.y >= 0) {
+    return;
+  }
+
+  // easing function (based on github.com/robb/RBBAnimation)
+  CGFloat(^RBBEasingFunctionEaseOutBounce)(CGFloat) = ^CGFloat(CGFloat t) {
+    if (t < 4.0 / 11.0) return pow(11.0 / 4.0, 2) * pow(t, 2);
+    if (t < 8.0 / 11.0) return 3.0 / 4.0 + pow(11.0 / 4.0, 2) * pow(t - 6.0 / 11.0, 2);
+    if (t < 10.0 / 11.0) return 15.0 /16.0 + pow(11.0 / 4.0, 2) * pow(t - 9.0 / 11.0, 2);
+    return 63.0 / 64.0 + pow(11.0 / 4.0, 2) * pow(t - 21.0 / 22.0, 2);
+  };
+
+  // create values
+  int fromCenterY=-20, toCenterY=0, animationSteps=100;
+  NSMutableArray *values = [NSMutableArray arrayWithCapacity:animationSteps];
+  for (int t = 1; t<=animationSteps; t++) {
+    float easedTime = RBBEasingFunctionEaseOutBounce((t*1.0)/animationSteps);
+    float easedValue = fromCenterY + easedTime * (toCenterY-fromCenterY);
+    [values addObject:[NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0, easedValue, 0)]];
+  }
+
+  // build animation
+  CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
+  animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
+  animation.duration = 0.66;
+  animation.values = values;
+  animation.removedOnCompletion = NO;
+  animation.fillMode = kCAFillModeForwards;
+  animation.delegate = self;
+  [self.topBar.layer setValue:@(toCenterY) forKeyPath:animation.keyPath];
+  [self.topBar.layer addAnimation:animation forKey:@"JDBounceAnimation"];
+}
+
+- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
+{
+  self.topBar.transform = CGAffineTransformIdentity;
+  [self.topBar.layer removeAllAnimations];
+}
+
+#pragma mark Progress & Activity
+
+- (void)setProgress:(CGFloat)progress;
+{
+  if (_topBar == nil) return;
+
+  // trim progress
+  _progress = MIN(1.0, MAX(0.0,progress));
+
+  if (_progress == 0.0) {
+    _progressView.frame = CGRectZero;
+    return;
+  }
+
+  // update superview
+  if (self.activeStyle.progressBarPosition == JDStatusBarProgressBarPositionBelow ||
+      self.activeStyle.progressBarPosition == JDStatusBarProgressBarPositionNavBar) {
+    [self.topBar.superview addSubview:self.progressView];
+  } else {
+    [self.topBar insertSubview:self.progressView belowSubview:self.topBar.textLabel];
+  }
+
+  // calculate progressView frame
+  CGRect frame = self.topBar.bounds;
+  CGFloat height = MIN(frame.size.height,MAX(0.5, self.activeStyle.progressBarHeight));
+  if (height == 20.0 && frame.size.height > height) height = frame.size.height;
+  frame.size.height = height;
+  frame.size.width = round((frame.size.width - 2 * self.activeStyle.progressBarHorizontalInsets) * progress);
+  frame.origin.x = self.activeStyle.progressBarHorizontalInsets;
+
+  // apply y-position from active style
+  CGFloat barHeight = self.topBar.bounds.size.height;
+  if (self.activeStyle.progressBarPosition == JDStatusBarProgressBarPositionBottom) {
+    frame.origin.y = barHeight - height;
+  } else if(self.activeStyle.progressBarPosition == JDStatusBarProgressBarPositionCenter) {
+    frame.origin.y = round((barHeight - height)/2.0);
+  } else if(self.activeStyle.progressBarPosition == JDStatusBarProgressBarPositionTop) {
+    frame.origin.y = 0.0;
+  } else if(self.activeStyle.progressBarPosition == JDStatusBarProgressBarPositionBelow) {
+    frame.origin.y = barHeight;
+  } else if(self.activeStyle.progressBarPosition == JDStatusBarProgressBarPositionNavBar) {
+    CGFloat navBarHeight = 44.0;
+    if (([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) &&
+        UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
+      navBarHeight = 32.0;
+    }
+    frame.origin.y = barHeight + navBarHeight;
+  }
+
+  // apply color from active style
+  self.progressView.backgroundColor = self.activeStyle.progressBarColor;
+
+  // apply corner radius
+  self.progressView.layer.cornerRadius = self.activeStyle.progressBarCornerRadius;
+
+  // update progressView frame
+  BOOL animated = !CGRectEqualToRect(self.progressView.frame, CGRectZero);
+  [UIView animateWithDuration:animated ? 0.05 : 0.0 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
+    self.progressView.frame = frame;
+  } completion:nil];
+}
+
+- (void)showActivityIndicator:(BOOL)show
+               indicatorStyle:(UIActivityIndicatorViewStyle)style;
+{
+  if (_topBar == nil) return;
+
+  if (show) {
+    [self.topBar.activityIndicatorView startAnimating];
+    self.topBar.activityIndicatorView.activityIndicatorViewStyle = style;
+  } else {
+    [self.topBar.activityIndicatorView stopAnimating];
+  }
+}
+
+#pragma mark State
+
+- (BOOL)isVisible;
+{
+  return (_topBar != nil);
+}
+
+#pragma mark Lazy views
+
+- (UIWindow *)overlayWindow;
+{
+  if(_overlayWindow == nil) {
+    _overlayWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
+    _overlayWindow.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+    _overlayWindow.backgroundColor = [UIColor clearColor];
+    _overlayWindow.userInteractionEnabled = NO;
+    _overlayWindow.windowLevel = UIWindowLevelStatusBar;
+    _overlayWindow.rootViewController = [[JDStatusBarNotificationViewController alloc] init];
+    _overlayWindow.rootViewController.view.backgroundColor = [UIColor clearColor];
+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 // only when deployment target is < ios7
+    _overlayWindow.rootViewController.wantsFullScreenLayout = YES;
+#endif
+    [self updateWindowTransform];
+    [self updateTopBarFrameWithStatusBarFrame:[[UIApplication sharedApplication] statusBarFrame]];
+  }
+  return _overlayWindow;
+}
+
+- (JDStatusBarView*)topBar;
+{
+  if(_topBar == nil) {
+    _topBar = [[JDStatusBarView alloc] init];
+    [self.overlayWindow.rootViewController.view addSubview:_topBar];
+
+    JDStatusBarStyle *style = self.activeStyle ?: self.defaultStyle;
+    if (style.animationType != JDStatusBarAnimationTypeFade) {
+      self.topBar.transform = CGAffineTransformMakeTranslation(0, -self.topBar.frame.size.height);
+    } else {
+      self.topBar.alpha = 0.0;
+    }
+  }
+  return _topBar;
+}
+
+- (UIView *)progressView;
+{
+  if (_progressView == nil) {
+    _progressView = [[UIView alloc] initWithFrame:CGRectZero];
+  }
+  return _progressView;
+}
+
+#pragma mark Rotation
+
+- (void)updateWindowTransform;
+{
+  UIWindow *window = [[UIApplication sharedApplication]
+                      mainApplicationWindowIgnoringWindow:self.overlayWindow];
+  _overlayWindow.transform = window.transform;
+  _overlayWindow.frame = window.frame;
+}
+
+- (void)updateTopBarFrameWithStatusBarFrame:(CGRect)rect;
+{
+  CGFloat width = MAX(rect.size.width, rect.size.height);
+  CGFloat height = MIN(rect.size.width, rect.size.height);
+
+  // on ios7 fix position, if statusBar has double height
+  CGFloat yPos = 0;
+  if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0 && height > 20.0) {
+    yPos = -height/2.0;
+  }
+
+  _topBar.frame = CGRectMake(0, yPos, width, height);
+}
+
+- (void)willChangeStatusBarFrame:(NSNotification*)notification;
+{
+  CGRect newBarFrame = [notification.userInfo[UIApplicationStatusBarFrameUserInfoKey] CGRectValue];
+  NSTimeInterval duration = [[UIApplication sharedApplication] statusBarOrientationAnimationDuration];
+
+  // update window & statusbar
+  void(^updateBlock)() = ^{
+    [self updateWindowTransform];
+    [self updateTopBarFrameWithStatusBarFrame:newBarFrame];
+    self.progress = self.progress; // // relayout progress bar
+  };
+
+  [UIView animateWithDuration:duration animations:^{
+    updateBlock();
+  } completion:^(BOOL finished) {
+    // this hack fixes a broken frame after the rotation (#35)
+    // but rotation animation is still broken
+    updateBlock();
+  }];
+}
+
+@end
+
+// A custom view controller, so the statusBarStyle & rotation behaviour is correct
+@implementation JDStatusBarNotificationViewController
+
+// rotation
+
+- (UIViewController*)mainController
+{
+  UIWindow *mainAppWindow = [[UIApplication sharedApplication] mainApplicationWindowIgnoringWindow:self.view.window];
+  UIViewController *topController = mainAppWindow.rootViewController;
+
+  while(topController.presentedViewController) {
+    topController = topController.presentedViewController;
+  }
+
+  return topController;
+}
+
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
+  return [[self mainController] shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
+}
+
+- (BOOL)shouldAutorotate {
+  return [[self mainController] shouldAutorotate];
+}
+
+#if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000
+- (NSUInteger)supportedInterfaceOrientations {
+#else
+  - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
+#endif
+    return [[self mainController] supportedInterfaceOrientations];
+  }
+
+  - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
+    return [[self mainController] preferredInterfaceOrientationForPresentation];
+  }
+
+  // statusbar
+
+  static BOOL JDUIViewControllerBasedStatusBarAppearanceEnabled() {
+    static BOOL enabled = NO;
+    static dispatch_once_t onceToken;
+
+    dispatch_once(&onceToken, ^{
+      enabled = [[[[NSBundle mainBundle] infoDictionary] objectForKey:@"UIViewControllerBasedStatusBarAppearance"] boolValue];
+    });
+
+    return enabled;
+  }
+
+  - (UIStatusBarStyle)preferredStatusBarStyle {
+    if(JDUIViewControllerBasedStatusBarAppearanceEnabled()) {
+      return [[self mainController] preferredStatusBarStyle];
+    }
+
+    return [[UIApplication sharedApplication] statusBarStyle];
+  }
+
+  - (BOOL)prefersStatusBarHidden {
+    return NO;
+  }
+
+  - (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
+    if(JDUIViewControllerBasedStatusBarAppearanceEnabled()) {
+      return [[self mainController] preferredStatusBarUpdateAnimation];
+    }
+    return [super preferredStatusBarUpdateAnimation];
+  }
+
+  @end
+
+  @implementation UIApplication (mainWindow)
+  // we don't want the keyWindow, since it could be our own window
+  - (UIWindow*)mainApplicationWindowIgnoringWindow:(UIWindow *)ignoringWindow {
+    for (UIWindow *window in [[UIApplication sharedApplication] windows]) {
+      if (!window.hidden && window != ignoringWindow) {
+        return window;
+      }
+    }
+    return nil;
+  }
+  @end

+ 77 - 0
Libraries external/JDStatusBarNotification/JDStatusBarStyle.h

@@ -0,0 +1,77 @@
+//
+//  JDStatusBarStyle.h
+//  JDStatusBarNotificationExample
+//
+//  Created by Markus on 04.12.13.
+//  Copyright (c) 2013 Markus. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+extern NSString *const JDStatusBarStyleError;   /// This style has a red background with a white Helvetica label.
+extern NSString *const JDStatusBarStyleWarning; /// This style has a yellow background with a gray Helvetica label.
+extern NSString *const JDStatusBarStyleSuccess; /// This style has a green background with a white Helvetica label.
+extern NSString *const JDStatusBarStyleMatrix;  /// This style has a black background with a green bold Courier label.
+extern NSString *const JDStatusBarStyleDefault; /// This style has a white background with a gray Helvetica label.
+extern NSString *const JDStatusBarStyleDark;    /// This style has a nearly black background with a nearly white Helvetica label.
+
+typedef NS_ENUM(NSInteger, JDStatusBarAnimationType) {
+    JDStatusBarAnimationTypeNone,   /// Notification won't animate
+    JDStatusBarAnimationTypeMove,   /// Notification will move in from the top, and move out again to the top
+    JDStatusBarAnimationTypeBounce, /// Notification will fall down from the top and bounce a little bit
+    JDStatusBarAnimationTypeFade    /// Notification will fade in and fade out
+};
+
+typedef NS_ENUM(NSInteger, JDStatusBarProgressBarPosition) {
+    JDStatusBarProgressBarPositionBottom, /// progress bar will be at the bottom of the status bar
+    JDStatusBarProgressBarPositionCenter, /// progress bar will be at the center of the status bar
+    JDStatusBarProgressBarPositionTop,    /// progress bar will be at the top of the status bar
+    JDStatusBarProgressBarPositionBelow,  /// progress bar will be below the status bar (the prograss bar won't move with the statusbar in this case)
+    JDStatusBarProgressBarPositionNavBar, /// progress bar will be below the navigation bar (the prograss bar won't move with the statusbar in this case)
+};
+
+/**
+ *  A Style defines the appeareance of a notification.
+ */
+@interface JDStatusBarStyle : NSObject <NSCopying>
+
+/// The background color of the notification bar
+@property (nonatomic, strong) UIColor *barColor;
+
+/// The text color of the notification label
+@property (nonatomic, strong) UIColor *textColor;
+
+/// The text shadow of the notification label
+@property (nonatomic, strong) NSShadow *textShadow;
+
+/// The font of the notification label
+@property (nonatomic, strong) UIFont *font;
+
+/// A correction of the vertical label position in points. Default is 0.0
+@property (nonatomic, assign) CGFloat textVerticalPositionAdjustment;
+
+#pragma mark Animation
+
+/// The animation, that is used to present the notification
+@property (nonatomic, assign) JDStatusBarAnimationType animationType;
+
+#pragma mark Progress Bar
+
+/// The background color of the progress bar (on top of the notification bar)
+@property (nonatomic, strong) UIColor *progressBarColor;
+
+/// The height of the progress bar. Default is 1.0
+@property (nonatomic, assign) CGFloat progressBarHeight;
+
+/// The position of the progress bar. Default is JDStatusBarProgressBarPositionBottom
+@property (nonatomic, assign) JDStatusBarProgressBarPosition progressBarPosition;
+
+/// The insets of the progress bar. Default is 0.0
+@property (nonatomic, assign) CGFloat progressBarHorizontalInsets;
+
+/// The corner radius of the progress bar. Default is 0.0
+@property (nonatomic, assign) CGFloat progressBarCornerRadius;
+
+@end
+

+ 106 - 0
Libraries external/JDStatusBarNotification/JDStatusBarStyle.m

@@ -0,0 +1,106 @@
+//
+//  JDStatusBarStyle.m
+//  JDStatusBarNotificationExample
+//
+//  Created by Markus on 04.12.13.
+//  Copyright (c) 2013 Markus. All rights reserved.
+//
+
+#import "JDStatusBarStyle.h"
+
+NSString *const JDStatusBarStyleError   = @"JDStatusBarStyleError";
+NSString *const JDStatusBarStyleWarning = @"JDStatusBarStyleWarning";
+NSString *const JDStatusBarStyleSuccess = @"JDStatusBarStyleSuccess";
+NSString *const JDStatusBarStyleMatrix  = @"JDStatusBarStyleMatrix";
+NSString *const JDStatusBarStyleDefault = @"JDStatusBarStyleDefault";
+NSString *const JDStatusBarStyleDark    = @"JDStatusBarStyleDark";
+
+@implementation JDStatusBarStyle
+
+- (instancetype)copyWithZone:(NSZone*)zone;
+{
+  JDStatusBarStyle *style = [[[self class] allocWithZone:zone] init];
+  style.barColor = self.barColor;
+  style.textColor = self.textColor;
+  style.textShadow = self.textShadow;
+  style.font = self.font;
+  style.textVerticalPositionAdjustment = self.textVerticalPositionAdjustment;
+  style.animationType = self.animationType;
+  style.progressBarColor = self.progressBarColor;
+  style.progressBarHeight = self.progressBarHeight;
+  style.progressBarPosition = self.progressBarPosition;
+  return style;
+}
+
++ (NSArray*)allDefaultStyleIdentifier;
+{
+  return @[JDStatusBarStyleError, JDStatusBarStyleWarning,
+           JDStatusBarStyleSuccess, JDStatusBarStyleMatrix,
+           JDStatusBarStyleDark];
+}
+
++ (JDStatusBarStyle*)defaultStyleWithName:(NSString*)styleName;
+{
+  // setup default style
+  JDStatusBarStyle *style = [[JDStatusBarStyle alloc] init];
+  style.barColor = [UIColor whiteColor];
+  style.progressBarColor = [UIColor greenColor];
+  style.progressBarHeight = 1.0;
+  style.progressBarPosition = JDStatusBarProgressBarPositionBottom;
+  style.textColor = [UIColor grayColor];
+  style.font = [UIFont systemFontOfSize:12.0];
+  style.animationType = JDStatusBarAnimationTypeMove;
+
+  // JDStatusBarStyleDefault
+  if ([styleName isEqualToString:JDStatusBarStyleDefault]) {
+    return style;
+  }
+
+  // JDStatusBarStyleError
+  else if ([styleName isEqualToString:JDStatusBarStyleError]) {
+    style.barColor = [UIColor colorWithRed:0.588 green:0.118 blue:0.000 alpha:1.000];
+    style.textColor = [UIColor whiteColor];
+    style.progressBarColor = [UIColor redColor];
+    style.progressBarHeight = 2.0;
+    return style;
+  }
+
+  // JDStatusBarStyleWarning
+  else if ([styleName isEqualToString:JDStatusBarStyleWarning]) {
+    style.barColor = [UIColor colorWithRed:0.900 green:0.734 blue:0.034 alpha:1.000];
+    style.textColor = [UIColor darkGrayColor];
+    style.progressBarColor = style.textColor;
+    return style;
+  }
+
+  // JDStatusBarStyleSuccess
+  else if ([styleName isEqualToString:JDStatusBarStyleSuccess]) {
+    style.barColor = [UIColor colorWithRed:0.588 green:0.797 blue:0.000 alpha:1.000];
+    style.textColor = [UIColor whiteColor];
+    style.progressBarColor = [UIColor colorWithRed:0.106 green:0.594 blue:0.319 alpha:1.000];
+    style.progressBarHeight = 1.0+1.0/[[UIScreen mainScreen] scale];
+    return style;
+  }
+
+  // JDStatusBarStyleDark
+  else if ([styleName isEqualToString:JDStatusBarStyleDark]) {
+    style.barColor = [UIColor colorWithRed:0.050 green:0.078 blue:0.120 alpha:1.000];
+    style.textColor = [UIColor colorWithWhite:0.95 alpha:1.0];
+    style.progressBarHeight = 1.0+1.0/[[UIScreen mainScreen] scale];
+    return style;
+  }
+
+  // JDStatusBarStyleMatrix
+  else if ([styleName isEqualToString:JDStatusBarStyleMatrix]) {
+    style.barColor = [UIColor blackColor];
+    style.textColor = [UIColor greenColor];
+    style.font = [UIFont fontWithName:@"Courier-Bold" size:14.0];
+    style.progressBarColor = [UIColor greenColor];
+    style.progressBarHeight = 2.0;
+    return style;
+  }
+
+  return nil;
+}
+
+@end

+ 15 - 0
Libraries external/JDStatusBarNotification/JDStatusBarView.h

@@ -0,0 +1,15 @@
+//
+//  JDStatusBarView.h
+//  JDStatusBarNotificationExample
+//
+//  Created by Markus on 04.12.13.
+//  Copyright (c) 2013 Markus. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface JDStatusBarView : UIView
+@property (nonatomic, strong, readonly) UILabel *textLabel;
+@property (nonatomic, strong, readonly) UIActivityIndicatorView *activityIndicatorView;
+@property (nonatomic, assign) CGFloat textVerticalPositionAdjustment;
+@end

+ 95 - 0
Libraries external/JDStatusBarNotification/JDStatusBarView.m

@@ -0,0 +1,95 @@
+//
+//  JDStatusBarView.m
+//  JDStatusBarNotificationExample
+//
+//  Created by Markus on 04.12.13.
+//  Copyright (c) 2013 Markus. All rights reserved.
+//
+
+#import "JDStatusBarView.h"
+
+@interface JDStatusBarView ()
+@property (nonatomic, strong) UILabel *textLabel;
+@property (nonatomic, strong) UIActivityIndicatorView *activityIndicatorView;
+@end
+
+@implementation JDStatusBarView
+
+#pragma mark dynamic getter
+
+- (UILabel *)textLabel;
+{
+  if (_textLabel == nil) {
+    _textLabel = [[UILabel alloc] init];
+    _textLabel.backgroundColor = [UIColor clearColor];
+    _textLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
+    _textLabel.textAlignment = NSTextAlignmentCenter;
+    _textLabel.adjustsFontSizeToFitWidth = YES;
+    _textLabel.clipsToBounds = YES;
+    [self addSubview:_textLabel];
+  }
+  return _textLabel;
+}
+
+- (UIActivityIndicatorView *)activityIndicatorView;
+{
+  if (_activityIndicatorView == nil) {
+    _activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
+    _activityIndicatorView.transform = CGAffineTransformMakeScale(0.7, 0.7);
+    [self addSubview:_activityIndicatorView];
+  }
+  return _activityIndicatorView;
+}
+
+#pragma mark setter
+
+- (void)setTextVerticalPositionAdjustment:(CGFloat)textVerticalPositionAdjustment;
+{
+  _textVerticalPositionAdjustment = textVerticalPositionAdjustment;
+  [self setNeedsLayout];
+}
+
+#pragma mark layout
+
+- (void)layoutSubviews;
+{
+  [super layoutSubviews];
+
+  // label
+  self.textLabel.frame = CGRectMake(0, 1+self.textVerticalPositionAdjustment,
+                                    self.bounds.size.width, self.bounds.size.height-1);
+
+  // activity indicator
+  if (_activityIndicatorView ) {
+    CGSize textSize = [self currentTextSize];
+    CGRect indicatorFrame = _activityIndicatorView.frame;
+    indicatorFrame.origin.x = round((self.bounds.size.width - textSize.width)/2.0) - indicatorFrame.size.width - 8.0;
+    indicatorFrame.origin.y = ceil(1+(self.bounds.size.height - indicatorFrame.size.height)/2.0);
+    _activityIndicatorView.frame = indicatorFrame;
+  }
+}
+
+- (CGSize)currentTextSize;
+{
+  CGSize textSize = CGSizeZero;
+
+  // use new sizeWithAttributes: if possible
+  SEL selector = NSSelectorFromString(@"sizeWithAttributes:");
+  if ([self.textLabel.text respondsToSelector:selector]) {
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
+    NSDictionary *attributes = @{NSFontAttributeName:self.textLabel.font};
+    textSize = [self.textLabel.text sizeWithAttributes:attributes];
+#endif
+  }
+
+  // otherwise use old sizeWithFont:
+  else {
+#if __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 // only when deployment target is < ios7
+    textSize = [self.textLabel.text sizeWithFont:self.textLabel.font];
+#endif
+  }
+
+  return textSize;
+}
+
+@end

+ 26 - 0
Nextcloud.xcodeproj/project.pbxproj

@@ -509,6 +509,9 @@
 		F77D49A91DC238E500CDC568 /* loading@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = F77D49A71DC238E500CDC568 /* loading@2x.gif */; };
 		F78088EA1DD3A1DB005C5A7C /* cryptocloud.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = F78088E51DD3A1DB005C5A7C /* cryptocloud.xcdatamodeld */; };
 		F78088EB1DD3A1DB005C5A7C /* cryptocloud.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = F78088E51DD3A1DB005C5A7C /* cryptocloud.xcdatamodeld */; };
+		F78964AD1EBB576C00403E13 /* JDStatusBarNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = F78964A81EBB576C00403E13 /* JDStatusBarNotification.m */; };
+		F78964AE1EBB576C00403E13 /* JDStatusBarStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = F78964AA1EBB576C00403E13 /* JDStatusBarStyle.m */; };
+		F78964AF1EBB576C00403E13 /* JDStatusBarView.m in Sources */ = {isa = PBXBuildFile; fileRef = F78964AC1EBB576C00403E13 /* JDStatusBarView.m */; };
 		F78BFED41D3111B800E513CF /* LaunchScreenNextcloud.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78BFECA1D3111B800E513CF /* LaunchScreenNextcloud.xib */; };
 		F78BFEE11D31126B00E513CF /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F78BFEDE1D31126B00E513CF /* MainInterface.storyboard */; };
 		F7A13A031E7F3D5D00016680 /* CCProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = F7A13A001E7F3D5D00016680 /* CCProgressView.m */; };
@@ -1384,6 +1387,12 @@
 		F78316861C0CB3CA00C43975 /* CCShareUserOC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCShareUserOC.h; sourceTree = "<group>"; };
 		F78316871C0CB3CA00C43975 /* CCShareUserOC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCShareUserOC.m; sourceTree = "<group>"; };
 		F787E5581BC503ED00AFBFE1 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
+		F78964A71EBB576C00403E13 /* JDStatusBarNotification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JDStatusBarNotification.h; sourceTree = "<group>"; };
+		F78964A81EBB576C00403E13 /* JDStatusBarNotification.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JDStatusBarNotification.m; sourceTree = "<group>"; };
+		F78964A91EBB576C00403E13 /* JDStatusBarStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JDStatusBarStyle.h; sourceTree = "<group>"; };
+		F78964AA1EBB576C00403E13 /* JDStatusBarStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JDStatusBarStyle.m; sourceTree = "<group>"; };
+		F78964AB1EBB576C00403E13 /* JDStatusBarView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JDStatusBarView.h; sourceTree = "<group>"; };
+		F78964AC1EBB576C00403E13 /* JDStatusBarView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JDStatusBarView.m; sourceTree = "<group>"; };
 		F78BFECA1D3111B800E513CF /* LaunchScreenNextcloud.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreenNextcloud.xib; sourceTree = "<group>"; };
 		F78BFEDE1D31126B00E513CF /* MainInterface.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MainInterface.storyboard; sourceTree = "<group>"; };
 		F78F6FAE1CC8CCB700F4EA25 /* CCSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCSection.h; sourceTree = "<group>"; };
@@ -1737,6 +1746,7 @@
 				F73CCE221DC13788007E38D8 /* DZNEmptyDataSet */,
 				F7659A211DC0B726004860C4 /* EAIntroView */,
 				F7659A2A1DC0B72F004860C4 /* EARestrictedScrollView */,
+				F78964A61EBB576C00403E13 /* JDStatusBarNotification */,
 				F7659A2F1DC0B737004860C4 /* iRate */,
 				F70F04821C889183008DAB36 /* MBProgressHUD */,
 				F70F04BD1C889184008DAB36 /* NYXImagesKit */,
@@ -2858,6 +2868,19 @@
 			name = Table;
 			sourceTree = "<group>";
 		};
+		F78964A61EBB576C00403E13 /* JDStatusBarNotification */ = {
+			isa = PBXGroup;
+			children = (
+				F78964A71EBB576C00403E13 /* JDStatusBarNotification.h */,
+				F78964A81EBB576C00403E13 /* JDStatusBarNotification.m */,
+				F78964A91EBB576C00403E13 /* JDStatusBarStyle.h */,
+				F78964AA1EBB576C00403E13 /* JDStatusBarStyle.m */,
+				F78964AB1EBB576C00403E13 /* JDStatusBarView.h */,
+				F78964AC1EBB576C00403E13 /* JDStatusBarView.m */,
+			);
+			path = JDStatusBarNotification;
+			sourceTree = "<group>";
+		};
 		F7A139FE1E7F3D5D00016680 /* CCProgress */ = {
 			isa = PBXGroup;
 			children = (
@@ -4145,6 +4168,7 @@
 				F762CB671EACB7D400B38484 /* CGPDFDocument.m in Sources */,
 				F77B0E311D118A16002130FE /* CCExifGeo.m in Sources */,
 				F77B0E321D118A16002130FE /* HRCgUtil.m in Sources */,
+				F78964AE1EBB576C00403E13 /* JDStatusBarStyle.m in Sources */,
 				F7F06EB71DBFACC600099AE9 /* CTAssetsGridViewFooter.m in Sources */,
 				F762CBC01EACB89C00B38484 /* LMMediaPlayer.m in Sources */,
 				F7F06EB91DBFACC600099AE9 /* CTAssetsGridViewLayout.m in Sources */,
@@ -4275,6 +4299,7 @@
 				F7F06ECF1DBFACC600099AE9 /* CTAssetThumbnailView.m in Sources */,
 				F762CAF71EACB66200B38484 /* XLFormBaseCell.m in Sources */,
 				F7F06E9F1DBFACC600099AE9 /* CTAssetCheckmark.m in Sources */,
+				F78964AD1EBB576C00403E13 /* JDStatusBarNotification.m in Sources */,
 				F762CB151EACB66200B38484 /* XLFormRowNavigationAccessoryView.m in Sources */,
 				F7F54D081E5B14C800E19C62 /* MWGridViewController.m in Sources */,
 				F7F06E971DBFACC600099AE9 /* PHAssetCollection+CTAssetsPickerController.m in Sources */,
@@ -4303,6 +4328,7 @@
 				F77B0EBF1D118A16002130FE /* RNEncryptor.m in Sources */,
 				F7F06EBF1DBFACC600099AE9 /* CTAssetsPageViewController.m in Sources */,
 				F7F06EA11DBFACC600099AE9 /* CTAssetCollectionViewCell.m in Sources */,
+				F78964AF1EBB576C00403E13 /* JDStatusBarView.m in Sources */,
 				F7F54D0D1E5B14C800E19C62 /* MWZoomingScrollView.m in Sources */,
 				F762CB0B1EACB66200B38484 /* XLFormRowDescriptor.m in Sources */,
 				F762CB7A1EACB7D400B38484 /* UIXToolbarView.m in Sources */,

BIN
Nextcloud.xcodeproj/project.xcworkspace/xcuserdata/marinofaggiana.xcuserdatad/UserInterfaceState.xcuserstate


+ 11 - 7
iOSClient/AppDelegate.m

@@ -37,6 +37,7 @@
 #import "Firebase.h"
 #import <Fabric/Fabric.h>
 #import <Crashlytics/Crashlytics.h>
+#import "JDStatusBarNotification.h"
 
 #ifdef CUSTOM_BUILD
     #import "CustomSwift.h"
@@ -716,20 +717,23 @@
 
 - (void)messageNotification:(NSString *)title description:(NSString *)description visible:(BOOL)visible delay:(NSTimeInterval)delay type:(TWMessageBarMessageType)type errorCode:(NSInteger)errorcode
 {
-    title = [NSString stringWithFormat:@"%@\n",[CCUtility localizableBrand:title table:nil]];
-        
+    static NSInteger errorCodePrev = 0;
+    
     dispatch_async(dispatch_get_main_queue(), ^{
         
         if (visible) {
             
-            if (errorcode == kCFURLErrorNotConnectedToInternet) {
+            if (errorcode == kCFURLErrorNotConnectedToInternet || errorcode == k_CCErrorNetworkNowAvailable) {
+                
+                if (errorCodePrev != errorcode)
+                    [JDStatusBarNotification showWithStatus:NSLocalizedString(title, nil) dismissAfter:delay styleName:JDStatusBarStyleDefault];
                 
-                NSLog(@"[LOG] No internet connection");
+                errorCodePrev = errorcode;
                 
             } else {
-            
+                
                 [TWMessageBarManager sharedInstance].styleSheet = self;
-                [[TWMessageBarManager sharedInstance] showMessageWithTitle:title description:[CCUtility localizableBrand:description table:nil] type:type duration:delay];
+                [[TWMessageBarManager sharedInstance] showMessageWithTitle:[NSString stringWithFormat:@"%@\n",[CCUtility localizableBrand:title table:nil]] description:[CCUtility localizableBrand:description table:nil] type:type duration:delay];
             }
             
         } else {
@@ -1154,7 +1158,7 @@
         
         if (self.lastReachability == NO) {
             
-            [self messageNotification:@"_network_available_" description:nil visible:YES delay:k_dismissAfterSecond type:TWMessageBarMessageTypeInfo errorCode:0];
+            [self messageNotification:@"_network_available_" description:nil visible:YES delay:k_dismissAfterSecond type:TWMessageBarMessageTypeInfo errorCode:k_CCErrorNetworkNowAvailable];
             
             if (_activeMain)
                 [_activeMain performSelector:@selector(requestServerCapabilities) withObject:nil afterDelay:3];

+ 1 - 0
iOSClient/CCGlobal.h

@@ -141,6 +141,7 @@ extern NSString *const urlBaseUploadDB;
 #define k_CCErrorTaskDownloadNotFound                   -9998
 #define k_CCErrorFileUploadNotFound                     -9997
 #define k_CCErrorInternalError                          -9996
+#define k_CCErrorNetworkNowAvailable                    -9995
 
 // Search
 #define k_minCharsSearch                                2