Marino Faggiana 6 years ago
parent
commit
abe142430e
24 changed files with 1345 additions and 33 deletions
  1. 0 0
      Libraries external/PKDownloadButton/.gitkeep
  2. 19 0
      Libraries external/PKDownloadButton/CALayer+PKDownloadButtonAnimations.h
  3. 60 0
      Libraries external/PKDownloadButton/CALayer+PKDownloadButtonAnimations.m
  4. 18 0
      Libraries external/PKDownloadButton/NSLayoutConstraint+PKDownloadButton.h
  5. 99 0
      Libraries external/PKDownloadButton/NSLayoutConstraint+PKDownloadButton.m
  6. 20 0
      Libraries external/PKDownloadButton/PKBorderedButton.h
  7. 49 0
      Libraries external/PKDownloadButton/PKBorderedButton.m
  8. 20 0
      Libraries external/PKDownloadButton/PKCircleProgressView.h
  9. 180 0
      Libraries external/PKDownloadButton/PKCircleProgressView.m
  10. 18 0
      Libraries external/PKDownloadButton/PKCircleView.h
  11. 91 0
      Libraries external/PKDownloadButton/PKCircleView.m
  12. 52 0
      Libraries external/PKDownloadButton/PKDownloadButton.h
  13. 219 0
      Libraries external/PKDownloadButton/PKDownloadButton.m
  14. 42 0
      Libraries external/PKDownloadButton/PKMacros.h
  15. 25 0
      Libraries external/PKDownloadButton/PKPendingView.h
  16. 134 0
      Libraries external/PKDownloadButton/PKPendingView.m
  17. 18 0
      Libraries external/PKDownloadButton/PKStopDownloadButton.h
  18. 96 0
      Libraries external/PKDownloadButton/PKStopDownloadButton.m
  19. 16 0
      Libraries external/PKDownloadButton/UIImage+PKDownloadButton.h
  20. 49 0
      Libraries external/PKDownloadButton/UIImage+PKDownloadButton.m
  21. 68 0
      Nextcloud.xcodeproj/project.pbxproj
  22. 2 1
      iOSClient/Main/CCCellMainTransfer.h
  23. 32 21
      iOSClient/Main/CCCellMainTransfer.xib
  24. 18 11
      iOSClient/Main/CCMain.m

+ 0 - 0
Libraries external/PKDownloadButton/.gitkeep


+ 19 - 0
Libraries external/PKDownloadButton/CALayer+PKDownloadButtonAnimations.h

@@ -0,0 +1,19 @@
+//
+//  CALayer+PKDownloadButtonAnimations.h
+//  Download
+//
+//  Created by Pavel on 31/05/15.
+//  Copyright (c) 2015 Katunin. All rights reserved.
+//
+
+#import <QuartzCore/QuartzCore.h>
+
+@interface CALayer (PKDownloadButtonAnimations)
+
+- (void)addRotationAnimationWithKey:(NSString *)animationKey
+               fullRotationDuration:(NSTimeInterval)fullRotationDuration;
+- (void)removeRotationAnimationWithKey:(NSString *)animationKey;
+- (void)removeRotationAnimationWithKey:(NSString *)animationKey
+                  fullRotationDuration:(NSTimeInterval)fullRotationDuration;
+
+@end

+ 60 - 0
Libraries external/PKDownloadButton/CALayer+PKDownloadButtonAnimations.m

@@ -0,0 +1,60 @@
+//
+//  CALayer+PKDownloadButtonAnimations.m
+//  Download
+//
+//  Created by Pavel on 31/05/15.
+//  Copyright (c) 2015 Katunin. All rights reserved.
+//
+
+#import "CALayer+PKDownloadButtonAnimations.h"
+
+static NSString *kRorationEndKey = @"PKLayerRorationEndKey";
+
+@implementation CALayer (PKDownloadButtonAnimations)
+
+- (void)addRotationAnimationWithKey:(NSString *)animationKey fullRotationDuration:(NSTimeInterval)fullRotationDuration {
+    NSNumber *fromValue = [self.presentationLayer valueForKeyPath:@"transform.rotation"];
+    [self removeAnimationForKey:kRorationEndKey];
+    
+    CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
+    rotationAnimation.fromValue = fromValue;
+    rotationAnimation.toValue = @([rotationAnimation.fromValue floatValue] + (2. * M_PI));
+    rotationAnimation.duration = fullRotationDuration;
+    rotationAnimation.repeatCount = HUGE_VALF;
+    rotationAnimation.removedOnCompletion = NO;
+    
+    [self addAnimation:rotationAnimation forKey:animationKey];
+}
+
+- (void)removeRotationAnimationWithKey:(NSString *)animationKey {
+    [self removeRotationAnimationWithKey:animationKey fullRotationDuration:0.0];
+}
+
+- (void)removeRotationAnimationWithKey:(NSString *)animationKey fullRotationDuration:(NSTimeInterval)fullRotationDuration {
+    NSNumber *fromValue = [self.presentationLayer valueForKeyPath:@"transform.rotation"];
+    NSNumber *toValue = @((fromValue.doubleValue < 0.0) ? 0.0 : 2.0 * M_PI);
+    
+    [self removeAnimationForKey:animationKey];
+    
+    const NSTimeInterval animationDuration = ABS(toValue.doubleValue - fromValue.doubleValue) * (fullRotationDuration / (2.0 * M_PI));
+    
+    if (fromValue.doubleValue != 0.0 && ![fromValue isEqualToNumber:toValue] && animationDuration > 0.0) {
+        [CATransaction begin];
+        CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
+        rotationAnimation.fromValue = fromValue;
+        rotationAnimation.toValue = toValue;
+        rotationAnimation.duration = animationDuration;
+        
+        [CATransaction setCompletionBlock:^{
+            [self removeAnimationForKey:kRorationEndKey];
+        }];
+        
+        [self addAnimation:rotationAnimation forKey:kRorationEndKey];
+        [CATransaction commit];
+    }
+    else {
+        [self removeAnimationForKey:kRorationEndKey];
+    }
+}
+
+@end

+ 18 - 0
Libraries external/PKDownloadButton/NSLayoutConstraint+PKDownloadButton.h

@@ -0,0 +1,18 @@
+#import <UIKit/UIKit.h>
+
+@interface NSLayoutConstraint (PKDownloadButton)
+
++ (NSArray *)constraintsForWrappedSubview:(UIView *)view withInsets:(UIEdgeInsets)insets;
++ (NSArray *)horizontalConstraintsForWrappedSubview:(UIView *)view withInsets:(UIEdgeInsets)insets;
++ (NSArray *)verticalConstraintsForWrappedSubview:(UIView *)view withInsets:(UIEdgeInsets)insets;
++ (NSLayoutConstraint *)constraintForView:(UIView *)view withWidth:(CGFloat)width;
++ (NSLayoutConstraint *)constraintForView:(UIView *)view withHeight:(CGFloat)height;
++ (NSArray *)constraintsForView:(UIView *)view withSize:(CGSize)size;
++ (NSArray *)constraintsWithVisualFormat:(NSString *)format views:(NSDictionary *)views;
++ (NSLayoutConstraint *)constraintForCenterByYView:(UIView *)overlay withView:(UIView *)view;
++ (NSLayoutConstraint *)constraintForCenterByXView:(UIView *)overlay withView:(UIView *)view;
+// Constraints for center view above it's superview
++ (NSArray *)constraintsForCenterView:(UIView *)overlay;
++ (NSArray *)constraintsForCenterView:(UIView *)overlay withView:(UIView *)view;
+
+@end

+ 99 - 0
Libraries external/PKDownloadButton/NSLayoutConstraint+PKDownloadButton.m

@@ -0,0 +1,99 @@
+#import "NSLayoutConstraint+PKDownloadButton.h"
+
+@implementation NSLayoutConstraint (PKDownloadButton)
+
++ (NSArray *)constraintsForWrappedSubview:(UIView *)view withInsets:(UIEdgeInsets)insets {
+    NSArray *horizontalConstraints = [self horizontalConstraintsForWrappedSubview:view withInsets:insets];
+    NSArray *verticalConstraints = [self verticalConstraintsForWrappedSubview:view withInsets:insets];
+    NSMutableArray *resultArray = [NSMutableArray arrayWithCapacity:[horizontalConstraints count] + [verticalConstraints count]];
+    [resultArray addObjectsFromArray:horizontalConstraints];
+    [resultArray addObjectsFromArray:verticalConstraints];
+    return resultArray;
+}
+
++ (NSArray *)horizontalConstraintsForWrappedSubview:(UIView *)view withInsets:(UIEdgeInsets)insets {
+    NSString *horizontalConstraintsFormat = [NSString stringWithFormat:@"H:|-(%d)-[view]-(%d)-|",
+                                             (int)insets.left,
+                                             (int)roundf(insets.right)];
+    NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:horizontalConstraintsFormat
+                                                                             options:0
+                                                                             metrics:nil
+                                                                               views:NSDictionaryOfVariableBindings(view)];
+    return horizontalConstraints;
+}
+
++ (NSArray *)verticalConstraintsForWrappedSubview:(UIView *)view withInsets:(UIEdgeInsets)insets {
+    NSString *verticalConstraintsFormat = [NSString stringWithFormat:@"V:|-(%d)-[view]-(%d)-|", (int)insets.top, (int)insets.bottom];
+    NSArray *verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:verticalConstraintsFormat
+                                                                           options:0
+                                                                           metrics:nil
+                                                                             views:NSDictionaryOfVariableBindings(view)];
+    return verticalConstraints;
+}
+
++ (NSLayoutConstraint *)constraintForView:(UIView *)view withWidth:(CGFloat)width {
+    return [NSLayoutConstraint constraintWithItem:view
+                                        attribute:NSLayoutAttributeWidth
+                                        relatedBy:NSLayoutRelationEqual
+                                           toItem:nil
+                                        attribute:NSLayoutAttributeNotAnAttribute
+                                       multiplier:1.0
+                                         constant:width];
+}
+
++ (NSLayoutConstraint *)constraintForView:(UIView *)view withHeight:(CGFloat)height {
+    return [NSLayoutConstraint constraintWithItem:view
+                                        attribute:NSLayoutAttributeHeight
+                                        relatedBy:NSLayoutRelationEqual
+                                           toItem:nil
+                                        attribute:NSLayoutAttributeNotAnAttribute
+                                       multiplier:1.0
+                                         constant:height];
+}
+
++ (NSArray *)constraintsForView:(UIView *)view withSize:(CGSize)size {
+    NSLayoutConstraint *width = [NSLayoutConstraint constraintForView:view
+                                                            withWidth:size.width];
+    NSLayoutConstraint *height = [NSLayoutConstraint constraintForView:view
+                                                             withHeight:size.height];
+    return @[width, height];
+}
+
++ (NSArray *)constraintsWithVisualFormat:(NSString *)format views:(NSDictionary *)views {
+    return [self constraintsWithVisualFormat:format options:0 metrics:nil views:views];
+}
+
++ (NSLayoutConstraint *)constraintForCenterByXView:(UIView *)overlay withView:(UIView *)view {
+    return [NSLayoutConstraint constraintWithItem:overlay
+                                          attribute:NSLayoutAttributeCenterX
+                                          relatedBy:NSLayoutRelationEqual
+                                             toItem:view
+                                          attribute:NSLayoutAttributeCenterX
+                                         multiplier:1.0
+                                           constant:0.0];
+}
+
++ (NSLayoutConstraint *)constraintForCenterByYView:(UIView *)overlay withView:(UIView *)view {
+    return [NSLayoutConstraint constraintWithItem:overlay
+                                          attribute:NSLayoutAttributeCenterY
+                                          relatedBy:NSLayoutRelationEqual
+                                             toItem:view
+                                          attribute:NSLayoutAttributeCenterY
+                                         multiplier:1.0
+                                           constant:0.0];
+}
+
++ (NSArray *)constraintsForCenterView:(UIView *)overlay {
+    return [self constraintsForCenterView:overlay withView:overlay.superview];
+}
+
++ (NSArray *)constraintsForCenterView:(UIView *)overlay withView:(UIView *)view {
+    NSMutableArray *constraints = [NSMutableArray array];
+    
+    [constraints addObject:[self constraintForCenterByXView:overlay withView:view]];
+    [constraints addObject:[self constraintForCenterByYView:overlay withView:view]];
+    
+    return constraints;
+}
+
+@end

+ 20 - 0
Libraries external/PKDownloadButton/PKBorderedButton.h

@@ -0,0 +1,20 @@
+//
+//  PKBorderedButton.h
+//  Pods
+//
+//  Created by Holden, Ryan on 2/7/16.
+//
+//
+
+#import <UIKit/UIKit.h>
+
+@interface PKBorderedButton : UIButton
+
+@property (nonatomic) CGFloat cornerRadius;
+@property (nonatomic) CGFloat lineWidth;
+
+- (void)configureDefaultAppearance;
+
+- (void)cleanDefaultAppearance;
+
+@end

+ 49 - 0
Libraries external/PKDownloadButton/PKBorderedButton.m

@@ -0,0 +1,49 @@
+//
+//  PKBorderedButton.m
+//  Pods
+//
+//  Created by Holden, Ryan on 2/7/16.
+//
+//
+
+#import "PKBorderedButton.h"
+#import "UIImage+PKDownloadButton.h"
+
+@implementation PKBorderedButton
+
+- (void)setCornerRadius:(CGFloat)cornerRadius {
+    _cornerRadius = cornerRadius;
+    [self updateBackgroundImage];
+}
+
+- (void)setLineWidth:(CGFloat)lineWidth {
+    _lineWidth = lineWidth;
+    [self updateBackgroundImage];
+}
+
+- (void)configureDefaultAppearance {
+    [self setCornerRadius:4];
+    [self setLineWidth:1];
+}
+
+- (void)updateBackgroundImage {
+    [self setBackgroundImage:[UIImage borderedImageWithFill:nil radius:self.cornerRadius lineColor:self.tintColor lineWidth:self.lineWidth]
+                    forState:UIControlStateNormal];
+
+    [self setBackgroundImage:[UIImage borderedImageWithFill:self.tintColor radius:self.cornerRadius lineColor:self.tintColor lineWidth:self.lineWidth]
+                    forState:UIControlStateHighlighted];
+}
+
+- (void)tintColorDidChange {
+    [super tintColorDidChange];
+    [self updateBackgroundImage];
+}
+
+- (void)cleanDefaultAppearance {
+    [self setBackgroundImage:nil forState:UIControlStateNormal];
+    [self setBackgroundImage:nil forState:UIControlStateHighlighted];
+    [self setAttributedTitle:nil forState:UIControlStateNormal];
+    [self setAttributedTitle:nil forState:UIControlStateHighlighted];
+}
+
+@end

+ 20 - 0
Libraries external/PKDownloadButton/PKCircleProgressView.h

@@ -0,0 +1,20 @@
+//
+//  PKCircleProgressView.h
+//  PKDownloadButton
+//
+//  Created by Pavel on 28/05/15.
+//  Copyright (c) 2015 Katunin. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+IB_DESIGNABLE
+@interface PKCircleProgressView : UIView
+
+@property (nonatomic, assign) IBInspectable CGFloat progress; /// 0.f - 1.0f
+@property (nonatomic, assign) IBInspectable CGFloat filledLineWidth; /// 0.f +
+@property (nonatomic, assign) IBInspectable CGFloat emptyLineWidth; /// 0.f +
+@property (nonatomic, assign) IBInspectable CGFloat radius; /// 0.f +
+@property (nonatomic, assign) IBInspectable BOOL filledLineStyleOuter;
+
+@end

+ 180 - 0
Libraries external/PKDownloadButton/PKCircleProgressView.m

@@ -0,0 +1,180 @@
+//
+//  PKCircleProgressView.m
+//  PKDownloadButton
+//
+//  Created by Pavel on 28/05/15.
+//  Copyright (c) 2015 Katunin. All rights reserved.
+//
+
+#import "PKCircleProgressView.h"
+#import "PKCircleView.h"
+#import "NSLayoutConstraint+PKDownloadButton.h"
+
+static const CGFloat kDefaultRaduis = 13.f;
+static const CGFloat kDefaultFilledLineWidth = 3.f;
+static const CGFloat kDefaultEmptyLineWidth = 1.f;
+static const CGFloat kStartAngle = M_PI * 1.5;
+
+@interface PKCircleProgressView ()
+
+@property (nonatomic, assign) CGFloat startAngle;
+@property (nonatomic, assign) CGFloat endAngle;
+
+@property (nonatomic, weak) PKCircleView *emptyLineCircleView;
+@property (nonatomic, weak) PKCircleView *filledLineCircleView;
+
+@property (nonatomic, weak) NSLayoutConstraint *emptyLineCircleWidth;
+@property (nonatomic, weak) NSLayoutConstraint *emptyLineCircleHeight;
+
+@property (nonatomic, weak) NSLayoutConstraint *filledLineCircleWidth;
+@property (nonatomic, weak) NSLayoutConstraint *filledLineCircleHeight;
+
+@property (nonatomic, assign) CGFloat emptyLineCircleSize;
+@property (nonatomic, assign) CGFloat filledLineCircleSize;
+
+- (PKCircleView *)createEmptyLineCircleView;
+- (PKCircleView *)createFilledLineCircleView;
+
+- (NSArray *)createCircleConstraints;
+
+@end
+
+static PKCircleProgressView *CommonInit(PKCircleProgressView *self) {
+    if (self != nil) {
+        self.backgroundColor = [UIColor clearColor];
+        self.startAngle = kStartAngle;
+        self.endAngle = self.startAngle + (M_PI * 2);
+        self.clipsToBounds = NO;
+        
+        PKCircleView *emptyLineCircleView = [self createEmptyLineCircleView];
+        self.emptyLineCircleView = emptyLineCircleView;
+        emptyLineCircleView.translatesAutoresizingMaskIntoConstraints = NO;
+        [self addSubview:emptyLineCircleView];
+        
+        PKCircleView *filledLineCircleView = [self createFilledLineCircleView];
+        self.filledLineCircleView = filledLineCircleView;
+        filledLineCircleView.translatesAutoresizingMaskIntoConstraints = NO;
+        [self addSubview:filledLineCircleView];
+        
+        [self addConstraints:[self createCircleConstraints]];
+        
+        self.emptyLineWidth = kDefaultEmptyLineWidth;
+        self.filledLineWidth = kDefaultFilledLineWidth;
+        self.radius = kDefaultRaduis;
+    }
+    return self;
+}
+
+@implementation PKCircleProgressView
+
+#pragma mark - initilaization / deallocation
+
+- (id)initWithCoder:(NSCoder *)decoder {
+    return CommonInit([super initWithCoder:decoder]);
+}
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    return CommonInit([super initWithFrame:frame]);
+}
+
+#pragma mark - properties
+
+- (void)setEmptyLineCircleSize:(CGFloat)emptyLineCircleSize {
+    self.emptyLineCircleWidth.constant = emptyLineCircleSize;
+    self.emptyLineCircleHeight.constant = emptyLineCircleSize;
+}
+
+- (void)setFilledLineCircleSize:(CGFloat)filledLineCircleSize {
+    self.filledLineCircleWidth.constant = filledLineCircleSize;
+    self.filledLineCircleHeight.constant = filledLineCircleSize;
+}
+
+- (void)setProgress:(CGFloat)progress {
+    _progress = progress;
+    self.filledLineCircleView.startAngleRadians = self.startAngle;
+    self.filledLineCircleView.endAngleRadians = (self.endAngle - self.startAngle) * progress + self.startAngle;
+    
+    [self setNeedsDisplay];
+}
+
+- (void)setFilledLineWidth:(CGFloat)filledLineWidth {
+    _filledLineWidth = filledLineWidth;
+    self.filledLineCircleView.lineWidth = filledLineWidth;
+    [self setNeedsUpdateConstraints];
+}
+
+- (void)setEmptyLineWidth:(CGFloat)emptyLineWidth {
+    _emptyLineWidth = emptyLineWidth;
+    self.emptyLineCircleView.lineWidth = emptyLineWidth;
+    [self setNeedsUpdateConstraints];
+}
+
+- (void)setRadius:(CGFloat)radius {
+    _radius = radius;
+    [self setNeedsUpdateConstraints];
+}
+
+- (void)setFilledLineStyleOuter:(BOOL)filledLineStyleOuter {
+    _filledLineStyleOuter = filledLineStyleOuter;
+    [self setNeedsUpdateConstraints];
+}
+
+#pragma mark - UIView
+
+- (void)updateConstraints {
+    [super updateConstraints];
+    self.emptyLineCircleSize = self.radius * 2.f;
+    CGFloat deltaRaduis = 0.f;
+    if (self.filledLineStyleOuter) {
+        deltaRaduis = - self.emptyLineCircleView.lineWidth / 2.f + self.filledLineCircleView.lineWidth;
+    }
+    else {
+        deltaRaduis = - self.emptyLineCircleView.lineWidth / 2.f;
+    }
+    self.filledLineCircleSize = self.radius * 2.f + deltaRaduis * 2.f;
+}
+
+#pragma mark - private methods
+
+- (PKCircleView *)createEmptyLineCircleView {
+    PKCircleView *emptyCircelView = [[PKCircleView alloc] init];
+    
+    NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintForView:emptyCircelView
+                                                                      withWidth:0.f];
+    self.emptyLineCircleWidth = widthConstraint;
+    [emptyCircelView addConstraint:widthConstraint];
+    
+    NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintForView:emptyCircelView
+                                                                      withHeight:0.f];
+    self.emptyLineCircleHeight = heightConstraint;
+    [emptyCircelView addConstraint:heightConstraint];
+    
+    return emptyCircelView;
+}
+
+- (PKCircleView *)createFilledLineCircleView {
+    PKCircleView *filledCircelView = [[PKCircleView alloc] init];
+    
+    NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintForView:filledCircelView
+                                                                      withWidth:0.f];
+    self.filledLineCircleWidth = widthConstraint;
+    [filledCircelView addConstraint:widthConstraint];
+    
+    NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintForView:filledCircelView
+                                                                      withHeight:0.f];
+    self.filledLineCircleHeight = heightConstraint;
+    [filledCircelView addConstraint:heightConstraint];
+    
+    return filledCircelView;
+}
+
+- (NSArray *)createCircleConstraints {
+    NSMutableArray *constraints = [NSMutableArray array];
+    [constraints addObjectsFromArray:[NSLayoutConstraint constraintsForCenterView:self.emptyLineCircleView
+                                                                         withView:self]];
+    [constraints addObjectsFromArray:[NSLayoutConstraint constraintsForWrappedSubview:self.filledLineCircleView
+                                                                           withInsets:UIEdgeInsetsZero]];
+    return constraints;
+}
+
+@end

+ 18 - 0
Libraries external/PKDownloadButton/PKCircleView.h

@@ -0,0 +1,18 @@
+//
+//  PKCircleView.h
+//  Download
+//
+//  Created by Pavel on 30/05/15.
+//  Copyright (c) 2015 Katunin. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+IB_DESIGNABLE
+@interface PKCircleView : UIView
+
+@property (nonatomic, assign) IBInspectable CGFloat startAngleRadians;
+@property (nonatomic, assign) IBInspectable CGFloat endAngleRadians;
+@property (nonatomic, assign) IBInspectable CGFloat lineWidth;
+
+@end

+ 91 - 0
Libraries external/PKDownloadButton/PKCircleView.m

@@ -0,0 +1,91 @@
+//
+//  PKCircleView.m
+//  Download
+//
+//  Created by Pavel on 30/05/15.
+//  Copyright (c) 2015 Katunin. All rights reserved.
+//
+
+#import "PKCircleView.h"
+
+static const CGFloat kDefaultLineWidth = 1.f;
+
+@interface PKCircleView ()
+
+- (void)drawCircleRadius:(CGFloat)radius
+                    rect:(CGRect)rect
+              startAngle:(CGFloat)startAngle
+                endAngle:(CGFloat)endAngel
+               lineWidth:(CGFloat)lineWidth;
+
+@end
+
+static PKCircleView *CommonInit(PKCircleView *self) {
+    if (self != nil) {
+        self.backgroundColor = [UIColor clearColor];
+        self.startAngleRadians = M_PI * 1.5;
+        self.endAngleRadians = self.startAngleRadians + (M_PI * 2);
+        self.lineWidth = kDefaultLineWidth;
+    }
+    return self;
+}
+
+@implementation PKCircleView
+
+#pragma mark - initialization
+
+- (id)initWithCoder:(NSCoder *)decoder {
+    return CommonInit([super initWithCoder:decoder]);
+}
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    return CommonInit([super initWithFrame:frame]);
+}
+
+#pragma mark - properties
+
+- (void)setLineWidth:(CGFloat)lineWidth {
+    _lineWidth = lineWidth;
+    [self setNeedsDisplay];
+}
+
+- (void)setStartAngleRadians:(CGFloat)startAngleRadians {
+    _startAngleRadians = startAngleRadians;
+    [self setNeedsDisplay];
+}
+
+- (void)setEndAngleRadians:(CGFloat)endAngleRadians {
+    _endAngleRadians = endAngleRadians;
+    [self setNeedsDisplay];
+}
+
+#pragma mark - UIView
+
+- (void)drawRect:(CGRect)rect {
+    [self drawCircleRadius:MIN(rect.size.width / 2, rect.size.height / 2) - self.lineWidth / 2.f
+                      rect:rect
+                startAngle:self.startAngleRadians
+                  endAngle:self.endAngleRadians
+                 lineWidth:self.lineWidth];
+}
+
+#pragma mark - private methods
+
+- (void)drawCircleRadius:(CGFloat)radius
+                    rect:(CGRect)rect
+              startAngle:(CGFloat)startAngle
+                endAngle:(CGFloat)endAngel
+               lineWidth:(CGFloat)lineWidth {
+    UIBezierPath* bezierPath = [UIBezierPath bezierPath];
+    [self.tintColor setStroke];
+    [bezierPath addArcWithCenter:CGPointMake(rect.size.width / 2, rect.size.height / 2)
+                          radius:radius
+                      startAngle:startAngle
+                        endAngle:endAngel
+                       clockwise:YES];
+    
+    bezierPath.lineWidth = lineWidth;
+    [bezierPath stroke];
+}
+
+@end

+ 52 - 0
Libraries external/PKDownloadButton/PKDownloadButton.h

@@ -0,0 +1,52 @@
+//
+//  PKDownloadButton.h
+//  PKDownloadButton
+//
+//  Created by Pavel on 28/05/15.
+//  Copyright (c) 2015 Katunin. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+#import "PKStopDownloadButton.h"
+#import "PKBorderedButton.h"
+#import "PKCircleProgressView.h"
+#import "PKPendingView.h"
+
+typedef NS_ENUM(NSUInteger, PKDownloadButtonState) {
+    kPKDownloadButtonState_StartDownload,
+    kPKDownloadButtonState_Pending,
+    kPKDownloadButtonState_Downloading,
+    kPKDownloadButtonState_Downloaded
+};
+
+@class PKDownloadButton;
+
+typedef void(^DownloadButtonTappedCallback)(PKDownloadButton *downloadButton, PKDownloadButtonState state);
+
+@protocol PKDownloadButtonDelegate <NSObject>
+
+- (void)downloadButtonTapped:(PKDownloadButton *)downloadButton
+                currentState:(PKDownloadButtonState)state;
+
+@end
+
+IB_DESIGNABLE
+@interface PKDownloadButton : UIView
+
+@property (nonatomic, weak) IBOutlet id <PKDownloadButtonDelegate> delegate;
+@property (nonatomic, copy) DownloadButtonTappedCallback callback;
+
+@property (nonatomic, weak, readonly) PKBorderedButton *startDownloadButton;
+@property (nonatomic, weak, readonly) PKStopDownloadButton *stopDownloadButton;
+@property (nonatomic, weak, readonly) PKBorderedButton *downloadedButton;
+@property (nonatomic, weak, readonly) PKPendingView *pendingView;
+
+@property (nonatomic, assign) PKDownloadButtonState state;
+
+-(void)updateStartDownloadButtonText:(NSString *)title;
+-(void)updateDownloadedButtonText:(NSString *)title;
+-(void)updateStartDownloadButtonText:(NSString *)title font:(UIFont *)font;
+-(void)updateDownloadedButtonText:(NSString *)title font:(UIFont *)font;
+
+@end

+ 219 - 0
Libraries external/PKDownloadButton/PKDownloadButton.m

@@ -0,0 +1,219 @@
+//
+//  PKDownloadButton.m
+//  PKDownloadButton
+//
+//  Created by Pavel on 28/05/15.
+//  Copyright (c) 2015 Katunin. All rights reserved.
+//
+
+#import "PKDownloadButton.h"
+#import "PKMacros.h"
+#import "NSLayoutConstraint+PKDownloadButton.h"
+#import "UIImage+PKDownloadButton.h"
+#import "PKPendingView.h"
+
+@interface PKDownloadButton ()
+
+@property (nonatomic, weak) PKBorderedButton *startDownloadButton;
+@property (nonatomic, weak) PKStopDownloadButton *stopDownloadButton;
+@property (nonatomic, weak) PKBorderedButton *downloadedButton;
+@property (nonatomic, weak) PKPendingView *pendingView;
+
+@property (nonatomic, strong) NSMutableArray *stateViews;
+
+- (PKBorderedButton *)createStartDownloadButton;
+- (PKStopDownloadButton *)createStopDownloadButton;
+- (PKBorderedButton *)createDownloadedButton;
+- (PKPendingView *)createPendingView;
+
+- (void)currentButtonTapped:(id)sender;
+
+- (void)createSubviews;
+- (NSArray *)createConstraints;
+
+@end
+
+static PKDownloadButton *CommonInit(PKDownloadButton *self) {
+    if (self != nil) {
+        [self createSubviews];
+        [self addConstraints:[self createConstraints]];
+        
+        self.state = kPKDownloadButtonState_StartDownload;
+        self.backgroundColor = [UIColor clearColor];
+    }
+    return self;
+}
+
+@implementation PKDownloadButton
+
+#pragma mark - Properties
+
+- (void)setState:(PKDownloadButtonState)state {
+    _state = state;
+    
+    [self.stateViews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+        SafeObjClassCast(UIView, view, obj);
+        view.hidden = YES;
+    }];
+    
+    switch (state) {
+        case kPKDownloadButtonState_StartDownload:
+            self.startDownloadButton.hidden = NO;
+            break;
+        case kPKDownloadButtonState_Pending:
+            self.pendingView.hidden = NO;
+            [self.pendingView startSpin];
+            break;
+        case kPKDownloadButtonState_Downloading:
+            self.stopDownloadButton.hidden = NO;
+            self.stopDownloadButton.progress = 0.f;
+            break;
+        case kPKDownloadButtonState_Downloaded:
+            self.downloadedButton.hidden = NO;
+            break;
+        default:
+            NSAssert(NO, @"unsupported state");
+            break;
+    }
+}
+
+#pragma mark - Initialization
+
+- (id)initWithCoder:(NSCoder *)decoder {
+    return CommonInit([super initWithCoder:decoder]);
+}
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    return CommonInit([super initWithFrame:frame]);
+}
+
+- (void)tintColorDidChange {
+	[super tintColorDidChange];
+	
+    [self updateButton:self.startDownloadButton title:[self.startDownloadButton titleForState:UIControlStateNormal] font:self.startDownloadButton.titleLabel.font];
+	[self updateButton:self.downloadedButton title:[self.downloadedButton titleForState:UIControlStateNormal] font:self.downloadedButton.titleLabel.font];
+}
+
+
+#pragma mark - appearance
+
+-(void)updateStartDownloadButtonText:(NSString *)title {
+    [self updateButton:self.startDownloadButton title:title];
+}
+
+-(void)updateDownloadedButtonText:(NSString *)title {
+    [self updateButton:self.downloadedButton title:title];
+}
+
+
+-(void)updateStartDownloadButtonText:(NSString *)title font:(UIFont *)font {
+    [self updateButton:self.startDownloadButton title:title font: font];
+}
+
+-(void)updateDownloadedButtonText:(NSString *)title font:(UIFont *)font {
+    [self updateButton:self.downloadedButton title:title font: font];
+}
+
+
+- (void)updateButton:(UIButton *)button title:(NSString *)title {
+    [self updateButton:button title:title font:[UIFont systemFontOfSize:14.f]];
+}
+
+- (void)updateButton:(UIButton *)button title:(NSString *)title font:(UIFont *)font {
+    if (title == nil) {
+        title = @"";
+    }
+    
+    [button setTitle:title forState:UIControlStateNormal];
+    [button setTitleColor:self.tintColor forState:UIControlStateNormal];
+    [button setTitleColor:UIColor.whiteColor forState:UIControlStateHighlighted];
+    
+    button.titleLabel.font = font;
+}
+
+#pragma mark - private methods
+
+- (PKBorderedButton *)createStartDownloadButton {
+    PKBorderedButton *startDownloadButton = [PKBorderedButton buttonWithType:UIButtonTypeCustom];
+    [startDownloadButton configureDefaultAppearance];
+    
+	[self updateButton:startDownloadButton title:@"DOWNLOAD"];
+	
+    [startDownloadButton addTarget:self
+                            action:@selector(currentButtonTapped:)
+                  forControlEvents:UIControlEventTouchUpInside];
+    return startDownloadButton;
+}
+
+- (PKStopDownloadButton *)createStopDownloadButton {
+    PKStopDownloadButton *stopDownloadButton = [[PKStopDownloadButton alloc] init];
+    [stopDownloadButton.stopButton addTarget:self action:@selector(currentButtonTapped:)
+                            forControlEvents:UIControlEventTouchUpInside];
+    return stopDownloadButton;
+}
+
+- (PKBorderedButton *)createDownloadedButton {
+    PKBorderedButton *downloadedButton = [PKBorderedButton buttonWithType:UIButtonTypeCustom];
+    [downloadedButton configureDefaultAppearance];
+
+	[self updateButton:downloadedButton title:@"REMOVE"];
+    
+    [downloadedButton addTarget:self
+                         action:@selector(currentButtonTapped:)
+               forControlEvents:UIControlEventTouchUpInside];
+    return downloadedButton;
+}
+
+- (PKPendingView *)createPendingView {
+    PKPendingView *pendingView = [[PKPendingView alloc] init];
+    [pendingView addTarget:self action:@selector(currentButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
+    return pendingView;
+}
+
+- (void)currentButtonTapped:(id)sender {
+    [self.delegate downloadButtonTapped:self currentState:self.state];
+    BlockSafeRun(self.callback, self, self.state);
+}
+
+- (void)createSubviews {
+    self.stateViews = (__bridge_transfer NSMutableArray *)CFArrayCreateMutable(nil, 0, nil);
+    
+    PKBorderedButton *startDownloadButton = [self createStartDownloadButton];
+    startDownloadButton.translatesAutoresizingMaskIntoConstraints = NO;
+    [self addSubview:startDownloadButton];
+    self.startDownloadButton = startDownloadButton;
+    [self.stateViews addObject:startDownloadButton];
+    
+    PKStopDownloadButton *stopDownloadButton = [self createStopDownloadButton];
+    stopDownloadButton.translatesAutoresizingMaskIntoConstraints = NO;
+    [self addSubview:stopDownloadButton];
+    self.stopDownloadButton = stopDownloadButton;
+    [self.stateViews addObject:stopDownloadButton];
+    
+    PKBorderedButton *downloadedButton = [self createDownloadedButton];
+    downloadedButton.translatesAutoresizingMaskIntoConstraints = NO;
+    [self addSubview:downloadedButton];
+    self.downloadedButton = downloadedButton;
+    [self.stateViews addObject:downloadedButton];
+    
+    PKPendingView *pendingView = [self createPendingView];
+    pendingView.translatesAutoresizingMaskIntoConstraints = NO;
+    [self addSubview:pendingView];
+    self.pendingView = pendingView;
+    [self.stateViews addObject:pendingView];
+}
+
+- (NSArray *)createConstraints {
+    NSMutableArray *constraints = [NSMutableArray array];
+    
+    [self.stateViews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+        SafeObjClassCast(UIView, view, obj);
+        [constraints addObjectsFromArray:[NSLayoutConstraint constraintsForWrappedSubview:view
+                                                                               withInsets:UIEdgeInsetsZero]];
+    }];
+    
+    return constraints;
+}
+
+@end
+

+ 42 - 0
Libraries external/PKDownloadButton/PKMacros.h

@@ -0,0 +1,42 @@
+//
+//  PKMacros.h
+//  Download
+//
+//  Created by Pavel on 30/05/15.
+//  Copyright (c) 2015 Katunin. All rights reserved.
+//
+
+#ifndef Download_PKMacros_h
+#define Download_PKMacros_h
+
+#pragma mark - Block helpers
+
+#define BlockSafeRun(block_, ...) do { if ((block_) != NULL) (block_)(__VA_ARGS__); } while (NO)
+#define BlockSafeRunEx(defaultValue_, block_, ...) (((block_) != NULL) ? (block_)(__VA_ARGS__) : (defaultValue_))
+#define BlockSafeRunOnTargetQueue(queue, block, ...) do { if ((block) != NULL) dispatch_async(queue, ^{ (block)(__VA_ARGS__); }); } while (0)
+#define BlockSafeRunOnMainQueue(block, ...) BlockSafeRunOnTargetQueue(dispatch_get_main_queue(), (block), __VA_ARGS__)
+
+#if __has_feature(objc_arc)
+#define BlockWeakObject(o) __typeof__(o) __weak
+#define BlockWeakSelf BlockWeakObject(self)
+#define BlockStrongObject(o) __typeof__(o) __strong
+#define BlockStrongSelf BlockStrongObject(self)
+#define WeakifySelf BlockWeakSelf ___weakSelf___ = self; do {} while (0)
+#define StrongifySelf BlockStrongSelf self = ___weakSelf___; do {} while (0)
+
+#endif // __has_feature(objc_arc)
+
+#define SafeObjClassCast(destClass_, resultObj_, originalObj_) \
+destClass_ *resultObj_ = (destClass_ *)originalObj_;\
+NSAssert2((resultObj_) == nil || [(resultObj_) isKindOfClass:[destClass_ class]],\
+@"Incorrect cast: original object (%@) could not be casted to the destination class (%@)", \
+(originalObj_), NSStringFromClass([destClass_ class]))
+
+#define SafeObjProtocolCast(destProtocol_, resultObj_, originalObj_) \
+id <destProtocol_> resultObj_ = (id <destProtocol_>)originalObj_;\
+NSAssert2((resultObj_) == nil || [(resultObj_) conformsToProtocol:@protocol(destProtocol_)],\
+@"Incorrect cast: original object (%@) could not be casted to the destination protocol (%@)", \
+(originalObj_), NSStringFromProtocol(@protocol(destProtocol_)))
+
+
+#endif // Download_PKMacros_h

+ 25 - 0
Libraries external/PKDownloadButton/PKPendingView.h

@@ -0,0 +1,25 @@
+//
+//  PKPendingView.h
+//  Download
+//
+//  Created by Pavel on 30/05/15.
+//  Copyright (c) 2015 Katunin. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "PKCircleView.h"
+
+IB_DESIGNABLE
+@interface PKPendingView : UIControl
+
+@property (nonatomic, weak, readonly) PKCircleView *circleView;
+
+@property (nonatomic, assign) IBInspectable CGFloat radius;
+@property (nonatomic, assign) IBInspectable CGFloat lineWidth;
+@property (nonatomic, assign) IBInspectable CGFloat emptyLineRadians;
+@property (nonatomic, assign) IBInspectable CGFloat spinTime;
+
+- (void)startSpin;
+- (void)stopSpin;
+
+@end

+ 134 - 0
Libraries external/PKDownloadButton/PKPendingView.m

@@ -0,0 +1,134 @@
+//
+//  PKPendingView.m
+//  Download
+//
+//  Created by Pavel on 30/05/15.
+//  Copyright (c) 2015 Katunin. All rights reserved.
+//
+
+#import "PKPendingView.h"
+#import "NSLayoutConstraint+PKDownloadButton.h"
+#import "CALayer+PKDownloadButtonAnimations.h"
+
+static NSString *const kSpinAnimationKey = @"PKSpin";
+static const CGFloat kDefaultRaduis = 13.f;
+static const CGFloat kDefaultEmptyLineRadians = 0.4f;
+static const CGFloat kDefaultSpinTime = 1.f;
+
+@interface PKPendingView ()
+
+@property (nonatomic, weak) PKCircleView *circleView;
+@property (nonatomic, weak) NSLayoutConstraint *width;
+@property (nonatomic, weak) NSLayoutConstraint *height;
+@property (nonatomic, assign) BOOL isSpinning;
+
+- (PKCircleView *)createCircleView;
+
+- (NSArray *)createConstraints;
+
+@end
+
+static PKPendingView *CommonInit(PKPendingView *self) {
+    if (self != nil) {
+        PKCircleView *circleView = [self createCircleView];
+        circleView.translatesAutoresizingMaskIntoConstraints = NO;
+        [self addSubview:circleView];
+        self.circleView = circleView;
+        self.circleView.userInteractionEnabled = NO;
+        [self addConstraints:[self createConstraints]];
+        
+        self.emptyLineRadians = kDefaultEmptyLineRadians;
+        self.radius = kDefaultRaduis;
+        self.clipsToBounds = NO;
+        
+        self.spinTime = kDefaultSpinTime;
+        [self startSpin];
+    }
+    return self;
+}
+
+@implementation PKPendingView
+
+#pragma mark - initialization
+
+- (id)initWithCoder:(NSCoder *)decoder {
+    return CommonInit([super initWithCoder:decoder]);
+}
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    return CommonInit([super initWithFrame:frame]);
+}
+
+#pragma mark - properties
+
+- (void)setSpinTime:(CGFloat)spinTime {
+    _spinTime = spinTime;
+    [self.circleView.layer removeRotationAnimationWithKey:kSpinAnimationKey];
+    if (self.isSpinning) {
+        [self startSpin];
+    }
+}
+
+- (void)setRadius:(CGFloat)radius {
+    self.width.constant = radius * 2;
+    self.height.constant = radius * 2;
+    [self setNeedsLayout];
+}
+
+- (void)setLineWidth:(CGFloat)lineWidth {
+    self.circleView.lineWidth = lineWidth;
+    [self setNeedsDisplay];
+}
+
+- (CGFloat)lineWidth {
+    return self.circleView.lineWidth;
+}
+
+- (void)setEmptyLineRadians:(CGFloat)emptyLineRadians {
+    _emptyLineRadians = emptyLineRadians;
+    self.circleView.startAngleRadians = 1.5f * M_PI + emptyLineRadians / 2.f;
+    self.circleView.endAngleRadians = self.circleView.startAngleRadians + 2 * M_PI - emptyLineRadians;
+    [self setNeedsDisplay];
+}
+
+- (void)setTintColor:(UIColor *)tintColor {
+    self.circleView.tintColor = tintColor;
+    [self setNeedsDisplay];
+}
+
+#pragma mark - private methods
+
+- (PKCircleView *)createCircleView {
+    PKCircleView *circleView = [[PKCircleView alloc] init];
+    NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintForView:circleView
+                                                                      withHeight:0.f];
+    NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintForView:circleView
+                                                                      withWidth:0.f];
+    
+    [circleView addConstraints:@[heightConstraint, widthConstraint]];
+    
+    self.width = widthConstraint;
+    self.height = heightConstraint;
+    
+    return circleView;
+}
+
+- (NSArray *)createConstraints {
+    NSMutableArray *constraints = [NSMutableArray array];
+    [constraints addObjectsFromArray:[NSLayoutConstraint constraintsForWrappedSubview:self.circleView
+                                                                           withInsets:UIEdgeInsetsZero]];
+    return constraints;
+}
+
+- (void)startSpin {
+    self.isSpinning = YES;
+    [self.circleView.layer addRotationAnimationWithKey:kSpinAnimationKey
+                                  fullRotationDuration:self.spinTime];
+}
+
+- (void)stopSpin {
+    [self.circleView.layer removeRotationAnimationWithKey:kSpinAnimationKey];
+    self.isSpinning = NO;
+}
+
+@end

+ 18 - 0
Libraries external/PKDownloadButton/PKStopDownloadButton.h

@@ -0,0 +1,18 @@
+//
+//  PKStopDownloadButton.h
+//  PKDownloadButton
+//
+//  Created by Pavel on 28/05/15.
+//  Copyright (c) 2015 Katunin. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "PKCircleProgressView.h"
+
+IB_DESIGNABLE
+@interface PKStopDownloadButton : PKCircleProgressView
+
+@property (nonatomic, assign) IBInspectable CGFloat stopButtonWidth;
+@property (nonatomic, weak, readonly) UIButton *stopButton;
+
+@end

+ 96 - 0
Libraries external/PKDownloadButton/PKStopDownloadButton.m

@@ -0,0 +1,96 @@
+//
+//  PKStopDownloadButton.m
+//  PKDownloadButton
+//
+//  Created by Pavel on 28/05/15.
+//  Copyright (c) 2015 Katunin. All rights reserved.
+//
+
+#import "PKStopDownloadButton.h"
+#import "NSLayoutConstraint+PKDownloadButton.h"
+#import "UIImage+PKDownloadButton.h"
+
+static const CGFloat kDefaultStopButtonWidth = 8.f;
+
+@interface PKStopDownloadButton ()
+
+@property (nonatomic, weak) UIButton *stopButton;
+
+- (UIButton *)createStopButton;
+- (NSArray *)createStopButtonConstraints;
+- (void)updateAppearance;
+- (PKCircleProgressView *)createCircleProgressView;
+
+@end
+
+static PKStopDownloadButton *CommonInit(PKStopDownloadButton *self) {
+    if (self != nil) {
+        UIButton *stopButton = [self createStopButton];
+        stopButton.translatesAutoresizingMaskIntoConstraints = NO;
+        [self addSubview:stopButton];
+        self.stopButton = stopButton;
+        
+        [self addConstraints:[self createStopButtonConstraints]];
+        [self updateAppearance];
+        [self setNeedsDisplay];
+    }
+    return self;
+}
+
+@implementation PKStopDownloadButton
+
+#pragma mark - properties
+
+- (void)setStopButtonWidth:(CGFloat)stopButtonWidth {
+    _stopButtonWidth = stopButtonWidth;
+    [self.stopButton setImage:[UIImage stopImageOfSize:stopButtonWidth
+                                                 color:self.tintColor]
+                     forState:UIControlStateNormal];
+    [self setNeedsDisplay];
+}
+
+#pragma mark - initialization
+
+- (instancetype)initWithCoder:(NSCoder *)decoder {
+    return CommonInit([super initWithCoder:decoder]);
+}
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    return CommonInit([super initWithFrame:frame]);
+}
+
+#pragma mark - private methods
+
+- (UIButton *)createStopButton {
+    UIButton *stopButton = [UIButton buttonWithType:UIButtonTypeCustom];
+	stopButton.tintColor = [UIColor clearColor];
+    _stopButtonWidth = kDefaultStopButtonWidth;
+    return stopButton;
+}
+
+- (NSArray *)createStopButtonConstraints {
+    NSMutableArray *constraints = [NSMutableArray array];
+    [constraints addObjectsFromArray:[NSLayoutConstraint constraintsForWrappedSubview:self.stopButton
+                                                                           withInsets:UIEdgeInsetsZero]];
+    
+    return constraints;
+}
+
+- (PKCircleProgressView *)createCircleProgressView {
+    PKCircleProgressView *circleProgressView = [[PKCircleProgressView alloc] init];
+    
+    return circleProgressView;
+}
+
+#pragma mark - appearance
+
+- (void)updateAppearance {
+	[self.stopButton setImage:[UIImage stopImageOfSize:_stopButtonWidth color:self.tintColor]
+				forState:UIControlStateNormal];
+}
+
+- (void)tintColorDidChange {
+	[super tintColorDidChange];
+	[self updateAppearance];
+}
+@end

+ 16 - 0
Libraries external/PKDownloadButton/UIImage+PKDownloadButton.h

@@ -0,0 +1,16 @@
+//
+//  UIImage+PKDownloadButton.h
+//  Download
+//
+//  Created by Pavel on 31/05/15.
+//  Copyright (c) 2015 Katunin. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface UIImage (PKDownloadButton)
+
++ (UIImage *)stopImageOfSize:(CGFloat)size color:(UIColor *)color;
++ (UIImage *)borderedImageWithFill:(UIColor *)fillColor radius:(CGFloat)radius lineColor:(UIColor *)lineColor lineWidth:(CGFloat)lineWidth;
+
+@end

+ 49 - 0
Libraries external/PKDownloadButton/UIImage+PKDownloadButton.m

@@ -0,0 +1,49 @@
+//
+//  UIImage+PKDownloadButton.m
+//  Download
+//
+//  Created by Pavel on 31/05/15.
+//  Copyright (c) 2015 Katunin. All rights reserved.
+//
+
+#import "UIImage+PKDownloadButton.h"
+
+@implementation UIImage (PKDownloadButton)
+
++ (UIImage *)stopImageOfSize:(CGFloat)size color:(UIColor *)color {
+    UIGraphicsBeginImageContextWithOptions(CGSizeMake(size, size), NO, 1.0f);
+    
+    CGContextRef context = UIGraphicsGetCurrentContext();
+    [color setStroke];
+    
+    CGRect stopImageRect = CGRectMake(0.f, 0.f, size, size);
+    CGContextSetFillColorWithColor(context, color.CGColor);
+    CGContextAddRect(context, stopImageRect);
+    CGContextFillRect(context, stopImageRect);
+    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+    
+    UIGraphicsEndImageContext();
+    return image;
+}
+
++ (UIImage *)borderedImageWithFill:(UIColor *)fillColor radius:(CGFloat)radius lineColor:(UIColor *)lineColor lineWidth:(CGFloat)lineWidth {
+
+    UIGraphicsBeginImageContextWithOptions(CGSizeMake(radius * 2, radius * 2), NO, 0.0f);
+
+    UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(lineWidth,lineWidth,(radius - lineWidth) * 2, (radius - lineWidth) * 2)
+                                                          cornerRadius:radius];
+    bezierPath.lineWidth = lineWidth;
+
+    if (lineColor) [lineColor setStroke];
+    if (fillColor) [fillColor setFill];
+
+    [bezierPath stroke];
+    
+    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+
+    UIGraphicsEndImageContext();
+
+    return [image resizableImageWithCapInsets:UIEdgeInsetsMake(radius, radius, radius, radius)];
+}
+
+@end

+ 68 - 0
Nextcloud.xcodeproj/project.pbxproj

@@ -390,6 +390,16 @@
 		F7BF1B431D51E893000854F6 /* CCLogin.m in Sources */ = {isa = PBXBuildFile; fileRef = F7BF1B401D51E893000854F6 /* CCLogin.m */; };
 		F7C525A01E3B48B700FFE02C /* CCNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C5259F1E3B48B700FFE02C /* CCNotification.swift */; };
 		F7C525A21E3B6DA800FFE02C /* CCNotification.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7C525A11E3B6DA800FFE02C /* CCNotification.storyboard */; };
+		F7CA1ED020E7E3FE002CC65E /* UIImage+PKDownloadButton.m in Sources */ = {isa = PBXBuildFile; fileRef = F7CA1EBC20E7E3FE002CC65E /* UIImage+PKDownloadButton.m */; };
+		F7CA1ED120E7E3FE002CC65E /* PKCircleProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = F7CA1EBE20E7E3FE002CC65E /* PKCircleProgressView.m */; };
+		F7CA1ED220E7E3FE002CC65E /* PKCircleView.m in Sources */ = {isa = PBXBuildFile; fileRef = F7CA1EC120E7E3FE002CC65E /* PKCircleView.m */; };
+		F7CA1ED320E7E3FE002CC65E /* PKStopDownloadButton.m in Sources */ = {isa = PBXBuildFile; fileRef = F7CA1EC220E7E3FE002CC65E /* PKStopDownloadButton.m */; };
+		F7CA1ED420E7E3FE002CC65E /* PKPendingView.m in Sources */ = {isa = PBXBuildFile; fileRef = F7CA1EC320E7E3FE002CC65E /* PKPendingView.m */; };
+		F7CA1ED520E7E3FE002CC65E /* .gitkeep in Resources */ = {isa = PBXBuildFile; fileRef = F7CA1EC520E7E3FE002CC65E /* .gitkeep */; };
+		F7CA1ED620E7E3FE002CC65E /* CALayer+PKDownloadButtonAnimations.m in Sources */ = {isa = PBXBuildFile; fileRef = F7CA1EC720E7E3FE002CC65E /* CALayer+PKDownloadButtonAnimations.m */; };
+		F7CA1ED720E7E3FE002CC65E /* PKDownloadButton.m in Sources */ = {isa = PBXBuildFile; fileRef = F7CA1EC820E7E3FE002CC65E /* PKDownloadButton.m */; };
+		F7CA1ED820E7E3FE002CC65E /* PKBorderedButton.m in Sources */ = {isa = PBXBuildFile; fileRef = F7CA1ECA20E7E3FE002CC65E /* PKBorderedButton.m */; };
+		F7CA1ED920E7E3FE002CC65E /* NSLayoutConstraint+PKDownloadButton.m in Sources */ = {isa = PBXBuildFile; fileRef = F7CA1ECE20E7E3FE002CC65E /* NSLayoutConstraint+PKDownloadButton.m */; };
 		F7D423331F0596AC009C9782 /* AppIcon-076.png in Resources */ = {isa = PBXBuildFile; fileRef = F7D423161F0596AC009C9782 /* AppIcon-076.png */; };
 		F7D423341F0596AC009C9782 /* AppIcon-120.png in Resources */ = {isa = PBXBuildFile; fileRef = F7D423171F0596AC009C9782 /* AppIcon-120.png */; };
 		F7D423351F0596AC009C9782 /* AppIcon-152.png in Resources */ = {isa = PBXBuildFile; fileRef = F7D423181F0596AC009C9782 /* AppIcon-152.png */; };
@@ -1323,6 +1333,26 @@
 		F7C742C01E7BD01F00D9C973 /* iOSClient.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = iOSClient.entitlements; sourceTree = "<group>"; };
 		F7C742D01E7BD35B00D9C973 /* Share.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Share.entitlements; sourceTree = "<group>"; };
 		F7C8C1901B482CEA0048180E /* CCGlobal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCGlobal.h; sourceTree = "<group>"; };
+		F7CA1EBC20E7E3FE002CC65E /* UIImage+PKDownloadButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+PKDownloadButton.m"; sourceTree = "<group>"; };
+		F7CA1EBD20E7E3FE002CC65E /* PKBorderedButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PKBorderedButton.h; sourceTree = "<group>"; };
+		F7CA1EBE20E7E3FE002CC65E /* PKCircleProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PKCircleProgressView.m; sourceTree = "<group>"; };
+		F7CA1EBF20E7E3FE002CC65E /* PKDownloadButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PKDownloadButton.h; sourceTree = "<group>"; };
+		F7CA1EC020E7E3FE002CC65E /* CALayer+PKDownloadButtonAnimations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CALayer+PKDownloadButtonAnimations.h"; sourceTree = "<group>"; };
+		F7CA1EC120E7E3FE002CC65E /* PKCircleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PKCircleView.m; sourceTree = "<group>"; };
+		F7CA1EC220E7E3FE002CC65E /* PKStopDownloadButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PKStopDownloadButton.m; sourceTree = "<group>"; };
+		F7CA1EC320E7E3FE002CC65E /* PKPendingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PKPendingView.m; sourceTree = "<group>"; };
+		F7CA1EC420E7E3FE002CC65E /* NSLayoutConstraint+PKDownloadButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSLayoutConstraint+PKDownloadButton.h"; sourceTree = "<group>"; };
+		F7CA1EC520E7E3FE002CC65E /* .gitkeep */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .gitkeep; sourceTree = "<group>"; };
+		F7CA1EC620E7E3FE002CC65E /* PKMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PKMacros.h; sourceTree = "<group>"; };
+		F7CA1EC720E7E3FE002CC65E /* CALayer+PKDownloadButtonAnimations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CALayer+PKDownloadButtonAnimations.m"; sourceTree = "<group>"; };
+		F7CA1EC820E7E3FE002CC65E /* PKDownloadButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PKDownloadButton.m; sourceTree = "<group>"; };
+		F7CA1EC920E7E3FE002CC65E /* PKCircleProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PKCircleProgressView.h; sourceTree = "<group>"; };
+		F7CA1ECA20E7E3FE002CC65E /* PKBorderedButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PKBorderedButton.m; sourceTree = "<group>"; };
+		F7CA1ECB20E7E3FE002CC65E /* UIImage+PKDownloadButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+PKDownloadButton.h"; sourceTree = "<group>"; };
+		F7CA1ECC20E7E3FE002CC65E /* PKStopDownloadButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PKStopDownloadButton.h; sourceTree = "<group>"; };
+		F7CA1ECD20E7E3FE002CC65E /* PKCircleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PKCircleView.h; sourceTree = "<group>"; };
+		F7CA1ECE20E7E3FE002CC65E /* NSLayoutConstraint+PKDownloadButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSLayoutConstraint+PKDownloadButton.m"; sourceTree = "<group>"; };
+		F7CA1ECF20E7E3FE002CC65E /* PKPendingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PKPendingView.h; sourceTree = "<group>"; };
 		F7CC04E31F5AD50D00378CEF /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/CTAssetsPicker.strings; sourceTree = "<group>"; };
 		F7CC04E41F5AD50D00378CEF /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/SwiftWebVC.strings; sourceTree = "<group>"; };
 		F7CC04E51F5AD50D00378CEF /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/BKPasscodeView.strings; sourceTree = "<group>"; };
@@ -1800,6 +1830,7 @@
 				F7DC5FD31F00F98B00A903C7 /* MGSwipeTableCell */,
 				F7B2DEEB1F976785007CF4D2 /* NYMnemonic */,
 				F7540EE11D5B238600C3FFA8 /* openssl */,
+				F7CA1EBB20E7E3FE002CC65E /* PKDownloadButton */,
 				F75037421DBFA91A008FB480 /* PureLayout */,
 				F70F05241C889184008DAB36 /* Reachability */,
 				F7DFE24E1EBDC3A400CF5202 /* Realm */,
@@ -2682,6 +2713,33 @@
 			name = "Supporting Files";
 			sourceTree = "<group>";
 		};
+		F7CA1EBB20E7E3FE002CC65E /* PKDownloadButton */ = {
+			isa = PBXGroup;
+			children = (
+				F7CA1EBC20E7E3FE002CC65E /* UIImage+PKDownloadButton.m */,
+				F7CA1EBD20E7E3FE002CC65E /* PKBorderedButton.h */,
+				F7CA1EBE20E7E3FE002CC65E /* PKCircleProgressView.m */,
+				F7CA1EBF20E7E3FE002CC65E /* PKDownloadButton.h */,
+				F7CA1EC020E7E3FE002CC65E /* CALayer+PKDownloadButtonAnimations.h */,
+				F7CA1EC120E7E3FE002CC65E /* PKCircleView.m */,
+				F7CA1EC220E7E3FE002CC65E /* PKStopDownloadButton.m */,
+				F7CA1EC320E7E3FE002CC65E /* PKPendingView.m */,
+				F7CA1EC420E7E3FE002CC65E /* NSLayoutConstraint+PKDownloadButton.h */,
+				F7CA1EC520E7E3FE002CC65E /* .gitkeep */,
+				F7CA1EC620E7E3FE002CC65E /* PKMacros.h */,
+				F7CA1EC720E7E3FE002CC65E /* CALayer+PKDownloadButtonAnimations.m */,
+				F7CA1EC820E7E3FE002CC65E /* PKDownloadButton.m */,
+				F7CA1EC920E7E3FE002CC65E /* PKCircleProgressView.h */,
+				F7CA1ECA20E7E3FE002CC65E /* PKBorderedButton.m */,
+				F7CA1ECB20E7E3FE002CC65E /* UIImage+PKDownloadButton.h */,
+				F7CA1ECC20E7E3FE002CC65E /* PKStopDownloadButton.h */,
+				F7CA1ECD20E7E3FE002CC65E /* PKCircleView.h */,
+				F7CA1ECE20E7E3FE002CC65E /* NSLayoutConstraint+PKDownloadButton.m */,
+				F7CA1ECF20E7E3FE002CC65E /* PKPendingView.h */,
+			);
+			path = PKDownloadButton;
+			sourceTree = "<group>";
+		};
 		F7D423151F0596AC009C9782 /* Graphics */ = {
 			isa = PBXGroup;
 			children = (
@@ -3370,6 +3428,7 @@
 				F732B3371E8045A1002B7D75 /* SwiftWebVC.strings in Resources */,
 				F7F54CF11E5B14C700E19C62 /* ImageSelectedSmallOn.png in Resources */,
 				F762CB1B1EACB66200B38484 /* XLForm.bundle in Resources */,
+				F7CA1ED520E7E3FE002CC65E /* .gitkeep in Resources */,
 				F762CB9A1EACB84400B38484 /* icon-success@2x.png in Resources */,
 				F77B0F551D118A16002130FE /* Error.strings in Resources */,
 				F77B0F571D118A16002130FE /* synchronizedcrypto.gif in Resources */,
@@ -3676,6 +3735,7 @@
 				F762CB021EACB66200B38484 /* XLFormSliderCell.m in Sources */,
 				F77B0E1B1D118A16002130FE /* CCGraphics.m in Sources */,
 				F70022CB1EC4C9100080073F /* OCSharedDto.m in Sources */,
+				F7CA1ED320E7E3FE002CC65E /* PKStopDownloadButton.m in Sources */,
 				F762CB111EACB66200B38484 /* NSString+XLFormAdditions.m in Sources */,
 				F762CB9B1EACB84400B38484 /* TWMessageBarManager.m in Sources */,
 				F7D423871F0596C6009C9782 /* ReaderThumbsView.m in Sources */,
@@ -3694,10 +3754,12 @@
 				F77B0E231D118A16002130FE /* CCSharePermissionOC.m in Sources */,
 				F78071211EDB135100EAFFF6 /* CCPhotos.m in Sources */,
 				F762CAF81EACB66200B38484 /* XLFormButtonCell.m in Sources */,
+				F7CA1ED120E7E3FE002CC65E /* PKCircleProgressView.m in Sources */,
 				F75AE3C71E9D12900088BB09 /* SwiftyAvatar.swift in Sources */,
 				F762CAFC1EACB66200B38484 /* XLFormImageCell.m in Sources */,
 				F70022D11EC4C9100080073F /* OCUserProfile.m in Sources */,
 				F73B4EF61F470D9100BBEE4B /* LangArabicModel.cpp in Sources */,
+				F7CA1ED420E7E3FE002CC65E /* PKPendingView.m in Sources */,
 				F73B4F0B1F470D9100BBEE4B /* nsGB2312Prober.cpp in Sources */,
 				F762CAFE1EACB66200B38484 /* XLFormLeftRightSelectorCell.m in Sources */,
 				F77B0E301D118A16002130FE /* CCHud.m in Sources */,
@@ -3789,6 +3851,7 @@
 				F762CB181EACB66200B38484 /* XLFormValidationStatus.m in Sources */,
 				F73B4EF91F470D9100BBEE4B /* LangEsperantoModel.cpp in Sources */,
 				F77B0E8F1D118A16002130FE /* CCSection.m in Sources */,
+				F7CA1ED720E7E3FE002CC65E /* PKDownloadButton.m in Sources */,
 				F72AAECB1E5C60C700BB17E1 /* AHKActionSheetViewController.m in Sources */,
 				F77B0E921D118A16002130FE /* CCCellMainTransfer.m in Sources */,
 				F7659A391DC0B737004860C4 /* iRate.m in Sources */,
@@ -3806,6 +3869,7 @@
 				F7D424651F063B82009C9782 /* CTAssetsGridView.m in Sources */,
 				F70022C21EC4C9100080073F /* OCNotifications.m in Sources */,
 				F70022BF1EC4C9100080073F /* OCFileDto.m in Sources */,
+				F7CA1ED020E7E3FE002CC65E /* UIImage+PKDownloadButton.m in Sources */,
 				F73B4F011F470D9100BBEE4B /* LangThaiModel.cpp in Sources */,
 				F70022DD1EC4C9100080073F /* OCWebDAVClient.m in Sources */,
 				F73B4F001F470D9100BBEE4B /* LangSpanishModel.cpp in Sources */,
@@ -3841,6 +3905,7 @@
 				F7D423821F0596C6009C9782 /* ReaderThumbCache.m in Sources */,
 				F70022A71EC4C9100080073F /* AFSecurityPolicy.m in Sources */,
 				F78964AF1EBB576C00403E13 /* JDStatusBarView.m in Sources */,
+				F7CA1ED220E7E3FE002CC65E /* PKCircleView.m in Sources */,
 				F7F54D0D1E5B14C800E19C62 /* MWZoomingScrollView.m in Sources */,
 				F762CB0B1EACB66200B38484 /* XLFormRowDescriptor.m in Sources */,
 				F7169A1C1EE590930086BD69 /* NCShares.m in Sources */,
@@ -3851,6 +3916,7 @@
 				F70022B61EC4C9100080073F /* OCCapabilities.m in Sources */,
 				F7D423811F0596C6009C9782 /* ReaderMainToolbar.m in Sources */,
 				F762CB131EACB66200B38484 /* XLFormRightDetailCell.m in Sources */,
+				F7CA1ED820E7E3FE002CC65E /* PKBorderedButton.m in Sources */,
 				F7D4237B1F0596C6009C9782 /* ReaderContentPage.m in Sources */,
 				F73B4F0A1F470D9100BBEE4B /* nsEUCTWProber.cpp in Sources */,
 				F762CB871EACB81000B38484 /* REMenu.m in Sources */,
@@ -3860,12 +3926,14 @@
 				F75AC2431F1F62450073EC19 /* NCManageAutoUploadFileName.swift in Sources */,
 				F7D424701F063B82009C9782 /* CTAssetsPickerNoAssetsView.m in Sources */,
 				F7D424591F063B82009C9782 /* PHImageManager+CTAssetsPickerController.m in Sources */,
+				F7CA1ED620E7E3FE002CC65E /* CALayer+PKDownloadButtonAnimations.m in Sources */,
 				F7ECBA6D1E239DCD003E6328 /* CCCreateCloud.swift in Sources */,
 				F70022FE1EC4C9100080073F /* UtilsFramework.m in Sources */,
 				F7D424561F063B82009C9782 /* NSNumberFormatter+CTAssetsPickerController.m in Sources */,
 				F70022AA1EC4C9100080073F /* AFURLRequestSerialization.m in Sources */,
 				F7D423851F0596C6009C9782 /* ReaderThumbRender.m in Sources */,
 				F72AAECA1E5C60C700BB17E1 /* AHKActionSheet.m in Sources */,
+				F7CA1ED920E7E3FE002CC65E /* NSLayoutConstraint+PKDownloadButton.m in Sources */,
 				F74E432620B5547700C2E54C /* NCNetworkingEndToEnd.m in Sources */,
 				F73B4F141F470D9100BBEE4B /* nsUTF8Prober.cpp in Sources */,
 				F70022C81EC4C9100080073F /* OCRichObjectStrings.m in Sources */,

+ 2 - 1
iOSClient/Main/CCCellMainTransfer.h

@@ -22,6 +22,7 @@
 //
 
 #import <UIKit/UIKit.h>
+#import "PKDownloadButton.h"
 
 @interface CCCellMainTransfer : UITableViewCell
 
@@ -31,6 +32,6 @@
 @property(nonatomic, weak) IBOutlet UILabel *labelTitle;
 @property(nonatomic, weak) IBOutlet UILabel *labelInfoFile;
 
-@property(nonatomic, weak) IBOutlet UIButton *cancelTaskButton;
+@property(nonatomic, weak) IBOutlet PKStopDownloadButton *transferButton;
 
 @end

+ 32 - 21
iOSClient/Main/CCCellMainTransfer.xib

@@ -18,42 +18,53 @@
                 <rect key="frame" x="0.0" y="0.0" width="600" height="59.5"/>
                 <autoresizingMask key="autoresizingMask"/>
                 <subviews>
-                    <label opaque="NO" userInteractionEnabled="NO" tag="101" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QNC-8X-DAC">
-                        <rect key="frame" x="65" y="13" width="474" height="18"/>
+                    <label opaque="NO" userInteractionEnabled="NO" tag="101" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QNC-8X-DAC" userLabel="labelTitle">
+                        <rect key="frame" x="65" y="13" width="478" height="18"/>
                         <fontDescription key="fontDescription" type="system" pointSize="15"/>
                         <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                         <nil key="highlightedColor"/>
                     </label>
-                    <label opaque="NO" userInteractionEnabled="NO" tag="102" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p7I-KN-FVZ">
-                        <rect key="frame" x="65" y="31" width="474" height="15"/>
+                    <label opaque="NO" userInteractionEnabled="NO" tag="102" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p7I-KN-FVZ" userLabel="labelInfoFile">
+                        <rect key="frame" x="65" y="31" width="478" height="15"/>
                         <fontDescription key="fontDescription" type="system" pointSize="12"/>
                         <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.63921568627450975" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                         <nil key="highlightedColor"/>
                     </label>
-                    <imageView userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5" userLabel="File">
+                    <imageView userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5" userLabel="file">
                         <rect key="frame" x="15" y="10" width="40" height="40"/>
                         <constraints>
                             <constraint firstAttribute="width" constant="40" id="kM5-Uf-S8Z"/>
                             <constraint firstAttribute="height" constant="40" id="l9C-BW-ogy"/>
                         </constraints>
                     </imageView>
-                    <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="DQR-yN-JaH" userLabel="Image">
+                    <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="DQR-yN-JaH" userLabel="status">
                         <rect key="frame" x="10" y="40" width="15" height="15"/>
                         <constraints>
                             <constraint firstAttribute="height" constant="15" id="bgo-QS-x7k"/>
                             <constraint firstAttribute="width" constant="15" id="g4P-aH-jOh"/>
                         </constraints>
                     </imageView>
-                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Kaz-0H-BSt" userLabel="Cancel Task Button">
-                        <rect key="frame" x="547" y="5" width="50" height="50"/>
-                        <constraints>
-                            <constraint firstAttribute="height" constant="50" id="7rT-Yp-IRn"/>
-                            <constraint firstAttribute="width" constant="50" id="Czm-WN-sbo"/>
-                        </constraints>
-                        <state key="normal">
-                            <color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                        </state>
-                    </button>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dhS-83-mLd" userLabel="transferButton" customClass="PKStopDownloadButton">
+                        <rect key="frame" x="551" y="9.5" width="39" height="39"/>
+                        <color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="number" keyPath="radius">
+                                <real key="value" value="20"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="number" keyPath="stopButtonWidth">
+                                <real key="value" value="12"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="number" keyPath="progress">
+                                <real key="value" value="0.20000000000000001"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="number" keyPath="filledLineWidth">
+                                <real key="value" value="2"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="number" keyPath="emptyLineWidth">
+                                <real key="value" value="1"/>
+                            </userDefinedRuntimeAttribute>
+                        </userDefinedRuntimeAttributes>
+                    </view>
                 </subviews>
                 <color key="tintColor" red="1" green="0.5" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                 <constraints>
@@ -62,22 +73,22 @@
                     <constraint firstAttribute="trailing" secondItem="5" secondAttribute="trailing" constant="545" id="1gX-zZ-TEK"/>
                     <constraint firstItem="p7I-KN-FVZ" firstAttribute="leading" secondItem="5" secondAttribute="trailing" constant="10" id="4Xt-42-ra7"/>
                     <constraint firstItem="5" firstAttribute="leading" secondItem="DQR-yN-JaH" secondAttribute="trailing" constant="-10" id="6Op-l4-GTN"/>
-                    <constraint firstItem="Kaz-0H-BSt" firstAttribute="leading" secondItem="p7I-KN-FVZ" secondAttribute="trailing" constant="8" id="BxA-Mn-Hrb"/>
                     <constraint firstItem="DQR-yN-JaH" firstAttribute="top" secondItem="5" secondAttribute="bottom" constant="-10" id="CGn-pQ-QmD"/>
                     <constraint firstItem="5" firstAttribute="centerY" secondItem="sQq-jC-UEV" secondAttribute="centerY" id="asW-ir-Cfb"/>
-                    <constraint firstItem="Kaz-0H-BSt" firstAttribute="centerY" secondItem="sQq-jC-UEV" secondAttribute="centerY" id="cB6-gr-b5f"/>
                     <constraint firstItem="QNC-8X-DAC" firstAttribute="top" secondItem="sQq-jC-UEV" secondAttribute="top" constant="13" id="d78-LV-sUw"/>
-                    <constraint firstItem="Kaz-0H-BSt" firstAttribute="leading" secondItem="QNC-8X-DAC" secondAttribute="trailing" constant="8" id="dPR-O3-hfC"/>
+                    <constraint firstItem="dhS-83-mLd" firstAttribute="centerY" secondItem="sQq-jC-UEV" secondAttribute="centerY" id="eA9-jd-n75"/>
+                    <constraint firstAttribute="trailing" secondItem="dhS-83-mLd" secondAttribute="trailing" constant="10" id="j62-Bl-LTq"/>
                     <constraint firstAttribute="bottom" secondItem="p7I-KN-FVZ" secondAttribute="bottom" constant="13.5" id="ofO-Ef-6wt"/>
-                    <constraint firstAttribute="trailing" secondItem="Kaz-0H-BSt" secondAttribute="trailing" constant="3" id="pZl-oE-hE9"/>
+                    <constraint firstItem="dhS-83-mLd" firstAttribute="leading" secondItem="QNC-8X-DAC" secondAttribute="trailing" constant="8" id="vgg-Ni-Tci"/>
+                    <constraint firstItem="dhS-83-mLd" firstAttribute="leading" secondItem="p7I-KN-FVZ" secondAttribute="trailing" constant="8" id="zUF-S2-yOW"/>
                 </constraints>
             </tableViewCellContentView>
             <connections>
-                <outlet property="cancelTaskButton" destination="Kaz-0H-BSt" id="W4F-Ub-Sjv"/>
                 <outlet property="file" destination="5" id="h6v-aL-JbR"/>
                 <outlet property="labelInfoFile" destination="p7I-KN-FVZ" id="bIH-yL-aSv"/>
                 <outlet property="labelTitle" destination="QNC-8X-DAC" id="coV-Xj-n1Q"/>
                 <outlet property="status" destination="DQR-yN-JaH" id="neR-jW-zwL"/>
+                <outlet property="transferButton" destination="dhS-83-mLd" id="eza-fH-eAU"/>
             </connections>
             <point key="canvasLocation" x="414" y="244"/>
         </tableViewCell>

+ 18 - 11
iOSClient/Main/CCMain.m

@@ -35,8 +35,9 @@
 #import "NCAutoUpload.h"
 #import "NCBridgeSwift.h"
 #import "NCNetworkingEndToEnd.h"
+#import "PKDownloadButton.h"
 
-@interface CCMain () <CCActionsDeleteDelegate, CCActionsRenameDelegate, CCActionsSearchDelegate, CCActionsDownloadThumbnailDelegate, CCActionsSettingFavoriteDelegate, UITextViewDelegate, createFormUploadAssetsDelegate, MGSwipeTableCellDelegate, CCLoginDelegate, CCLoginDelegateWeb>
+@interface CCMain () <CCActionsDeleteDelegate, CCActionsRenameDelegate, CCActionsSearchDelegate, CCActionsDownloadThumbnailDelegate, CCActionsSettingFavoriteDelegate, UITextViewDelegate, createFormUploadAssetsDelegate, MGSwipeTableCellDelegate, CCLoginDelegate, CCLoginDelegateWeb, PKDownloadButtonDelegate>
 {
     AppDelegate *appDelegate;
     
@@ -2171,6 +2172,11 @@
     }
 }
 
+- (void)downloadButtonTapped:(PKDownloadButton *)downloadButton currentState:(PKDownloadButtonState)state
+{
+    NSLog(@"s");
+}
+
 - (void)cancelTaskButton:(id)sender withEvent:(UIEvent *)event
 {
     UITouch *touch = [[event allTouches] anyObject];
@@ -4429,7 +4435,7 @@
         if (metadata.directory) {
             
             // lable Info
-            cell.labelInfoFile.text = [NSString stringWithFormat:@"%@ %@", [CCUtility dateDiff:metadata.date], [CCUtility transformedSize:metadata.size]];
+            cell.labelInfoFile.text = [CCUtility dateDiff:metadata.date];
             
             // File Image & Image Title Segue
             if (metadata.e2eEncrypted) {
@@ -4465,7 +4471,7 @@
             BOOL iconFileExists = [[NSFileManager defaultManager] fileExistsAtPath:[CCUtility getDirectoryProviderStorageIconFileID:metadata.fileID fileNameView:metadata.fileNameView]];
             
             // Lable Info
-            cell.labelInfoFile.text = [CCUtility dateDiff:metadata.date];
+            cell.labelInfoFile.text = [NSString stringWithFormat:@"%@ %@", [CCUtility dateDiff:metadata.date], [CCUtility transformedSize:metadata.size]];
             
             // File Image
             if (iconFileExists) {
@@ -4611,7 +4617,8 @@
             cell.labelInfoFile.enabled = NO;
             
             cell.userInteractionEnabled = NO;
-            cell.cancelTaskButton.enabled = NO;
+            
+//            cell.cancelTaskButton.enabled = NO;
             
         } else {
             
@@ -4619,7 +4626,7 @@
             cell.labelInfoFile.enabled = YES;
             
             cell.userInteractionEnabled = YES;
-            cell.cancelTaskButton.enabled = YES;
+//            cell.cancelTaskButton.enabled = YES;
         }
         
         // downloadFile
@@ -4627,8 +4634,8 @@
             
             cell.status.image = [UIImage imageNamed:@"statusdownload"];
             
-            [cell.cancelTaskButton setBackgroundImage:[UIImage imageNamed:@"taskCancelDownload"] forState:UIControlStateNormal];
-            cell.cancelTaskButton.hidden = NO;
+//            [cell.cancelTaskButton setBackgroundImage:[UIImage imageNamed:@"taskCancelDownload"] forState:UIControlStateNormal];
+//            cell.cancelTaskButton.hidden = NO;
         }
         
         // downloadFile Error
@@ -4648,8 +4655,8 @@
             
             cell.status.image = [UIImage imageNamed:@"statusupload"];
             
-            [cell.cancelTaskButton setBackgroundImage:[UIImage imageNamed:@"taskCancelUpload"] forState:UIControlStateNormal];
-            cell.cancelTaskButton.hidden = NO;
+//            [cell.cancelTaskButton setBackgroundImage:[UIImage imageNamed:@"taskCancelUpload"] forState:UIControlStateNormal];
+//            cell.cancelTaskButton.hidden = NO;
             
             if (!iconFileExists) {
                 cell.file.image = [CCGraphics changeThemingColorImage:[UIImage imageNamed:@"uploadCloud"] multiplier:2 color:[NCBrandColor sharedInstance].brandElement];
@@ -4676,11 +4683,11 @@
         }
         
         // gesture Transfer
-        [cell.cancelTaskButton addTarget:self action:@selector(cancelTaskButton:withEvent:) forControlEvents:UIControlEventTouchUpInside];
+//        [cell.cancelTaskButton addTarget:self action:@selector(cancelTaskButton:withEvent:) forControlEvents:UIControlEventTouchUpInside];
         
         UILongPressGestureRecognizer *cancelLongGesture = [UILongPressGestureRecognizer new];
         [cancelLongGesture addTarget:self action:@selector(cancelAllTask:)];
-        [cell.cancelTaskButton addGestureRecognizer:cancelLongGesture];
+//        [cell.cancelTaskButton addGestureRecognizer:cancelLongGesture];
         
         return cell;
     }