Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
|
|
@ -0,0 +1,40 @@
|
|||
#import "MWMButton.h"
|
||||
#import "MWMCircularProgressState.h"
|
||||
#import "UIImageView+Coloring.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class MWMCircularProgress;
|
||||
|
||||
typedef NSArray<NSNumber *> *MWMCircularProgressStateVec;
|
||||
|
||||
@protocol MWMCircularProgressProtocol<NSObject>
|
||||
|
||||
- (void)progressButtonPressed:(MWMCircularProgress *)progress;
|
||||
|
||||
@end
|
||||
|
||||
@interface MWMCircularProgress: NSObject<CAAnimationDelegate>
|
||||
|
||||
+ (instancetype)downloaderProgressForParentView:(UIView *)parentView;
|
||||
|
||||
@property(nonatomic) CGFloat progress;
|
||||
@property(nonatomic) MWMCircularProgressState state;
|
||||
@property(weak, nonatomic, nullable) id<MWMCircularProgressProtocol> delegate;
|
||||
|
||||
- (void)setSpinnerColoring:(MWMImageColoring)coloring;
|
||||
- (void)setSpinnerBackgroundColor:(UIColor *)backgroundColor;
|
||||
- (void)setInvertColor:(BOOL)invertColor;
|
||||
- (void)setCancelButtonHidden;
|
||||
|
||||
- (nonnull instancetype)init __attribute__((unavailable("init is not available")));
|
||||
- (nonnull instancetype)initWithParentView:(UIView *)parentView;
|
||||
|
||||
- (void)setImageName:(nullable NSString *)imageName
|
||||
forStates:(MWMCircularProgressStateVec)states;
|
||||
- (void)setColor:(UIColor *)color forStates:(MWMCircularProgressStateVec)states;
|
||||
- (void)setColoring:(MWMButtonColoring)coloring
|
||||
forStates:(MWMCircularProgressStateVec)states;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
#import "MWMCircularProgress.h"
|
||||
#import "MWMCircularProgressView.h"
|
||||
|
||||
@interface MWMCircularProgressView ()
|
||||
|
||||
@property(nonatomic) BOOL suspendRefreshProgress;
|
||||
|
||||
@end
|
||||
|
||||
@interface MWMCircularProgress ()
|
||||
|
||||
@property(nonatomic) IBOutlet MWMCircularProgressView * rootView;
|
||||
@property(nonatomic) NSNumber * nextProgressToAnimate;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMCircularProgress
|
||||
|
||||
+ (nonnull instancetype)downloaderProgressForParentView:(nonnull UIView *)parentView
|
||||
{
|
||||
MWMCircularProgress * progress = [[self alloc] initWithParentView:parentView];
|
||||
|
||||
progress.rootView.suspendRefreshProgress = YES;
|
||||
|
||||
[progress setImageName:@"ic_download"
|
||||
forStates:@[@(MWMCircularProgressStateNormal), @(MWMCircularProgressStateSelected)]];
|
||||
[progress setImageName:@"ic_close_spinner"
|
||||
forStates:@[@(MWMCircularProgressStateProgress), @(MWMCircularProgressStateSpinner)]];
|
||||
[progress setImageName:@"ic_download_error" forStates:@[@(MWMCircularProgressStateFailed)]];
|
||||
[progress setImageName:@"ic_check" forStates:@[@(MWMCircularProgressStateCompleted)]];
|
||||
|
||||
[progress setColoring:MWMButtonColoringBlack
|
||||
forStates:@[@(MWMCircularProgressStateNormal), @(MWMCircularProgressStateSelected),
|
||||
@(MWMCircularProgressStateProgress), @(MWMCircularProgressStateSpinner)]];
|
||||
[progress setColoring:MWMButtonColoringOther forStates:@[@(MWMCircularProgressStateFailed)]];
|
||||
[progress setColoring:MWMButtonColoringBlue forStates:@[@(MWMCircularProgressStateCompleted)]];
|
||||
|
||||
progress.rootView.suspendRefreshProgress = NO;
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
- (nonnull instancetype)initWithParentView:(nonnull UIView *)parentView
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
[[UINib nibWithNibName:NSStringFromClass([self class]) bundle:nil] instantiateWithOwner:self options:nil];
|
||||
[parentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
[parentView addSubview:self.rootView];
|
||||
self.rootView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self.rootView.topAnchor constraintEqualToAnchor:parentView.topAnchor].active = YES;
|
||||
[self.rootView.bottomAnchor constraintEqualToAnchor:parentView.bottomAnchor].active = YES;
|
||||
[self.rootView.leadingAnchor constraintEqualToAnchor:parentView.leadingAnchor].active = YES;
|
||||
[self.rootView.trailingAnchor constraintEqualToAnchor:parentView.trailingAnchor].active = YES;
|
||||
self.state = MWMCircularProgressStateNormal;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc { [self.rootView removeFromSuperview]; }
|
||||
- (void)reset
|
||||
{
|
||||
_progress = 0.;
|
||||
[self.rootView updatePath:0.];
|
||||
self.nextProgressToAnimate = nil;
|
||||
}
|
||||
|
||||
- (void)setSpinnerColoring:(MWMImageColoring)coloring
|
||||
{
|
||||
[self.rootView setSpinnerColoring:coloring];
|
||||
}
|
||||
|
||||
- (void)setSpinnerBackgroundColor:(nonnull UIColor *)backgroundColor
|
||||
{
|
||||
[self.rootView setSpinnerBackgroundColor:backgroundColor];
|
||||
}
|
||||
|
||||
- (void)setImageName:(nullable NSString *)imageName
|
||||
forStates:(MWMCircularProgressStateVec)states
|
||||
{
|
||||
for (NSNumber *state in states)
|
||||
[self.rootView setImageName:imageName forState:(MWMCircularProgressState)state.integerValue];
|
||||
}
|
||||
|
||||
- (void)setColor:(UIColor *)color forStates:(MWMCircularProgressStateVec)states
|
||||
{
|
||||
for (NSNumber *state in states)
|
||||
[self.rootView setColor:color forState:(MWMCircularProgressState)state.integerValue];
|
||||
}
|
||||
|
||||
- (void)setColoring:(MWMButtonColoring)coloring
|
||||
forStates:(MWMCircularProgressStateVec)states
|
||||
{
|
||||
for (NSNumber *state in states)
|
||||
[self.rootView setColoring:coloring forState:(MWMCircularProgressState)state.integerValue];
|
||||
}
|
||||
|
||||
- (void)setInvertColor:(BOOL)invertColor { self.rootView.isInvertColor = invertColor; }
|
||||
#pragma mark - Animation
|
||||
|
||||
- (void)animationDidStop:(CABasicAnimation *)anim finished:(BOOL)flag
|
||||
{
|
||||
if (self.nextProgressToAnimate)
|
||||
{
|
||||
self.progress = self.nextProgressToAnimate.doubleValue;
|
||||
self.nextProgressToAnimate = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)setCancelButtonHidden
|
||||
{
|
||||
self.rootView.buttonView.hidden = YES;
|
||||
}
|
||||
|
||||
- (IBAction)buttonTouchUpInside:(UIButton *)sender { [self.delegate progressButtonPressed:self]; }
|
||||
#pragma mark - Properties
|
||||
|
||||
- (void)setProgress:(CGFloat)progress
|
||||
{
|
||||
if (progress < _progress || progress <= 0)
|
||||
{
|
||||
self.state = MWMCircularProgressStateSpinner;
|
||||
return;
|
||||
}
|
||||
self.rootView.state = MWMCircularProgressStateProgress;
|
||||
if (self.rootView.animating)
|
||||
{
|
||||
if (progress > self.nextProgressToAnimate.floatValue)
|
||||
self.nextProgressToAnimate = @(progress);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.rootView animateFromValue:self->_progress toValue:progress];
|
||||
self->_progress = progress;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setState:(MWMCircularProgressState)state
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self reset];
|
||||
self.rootView.state = state;
|
||||
});
|
||||
}
|
||||
|
||||
- (MWMCircularProgressState)state { return self.rootView.state; }
|
||||
@end
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MWMCircularProgress">
|
||||
<connections>
|
||||
<outlet property="rootView" destination="2DE-Qh-89K" id="1DR-Lj-Wv9"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="2DE-Qh-89K" customClass="MWMCircularProgressView" propertyAccessControl="none">
|
||||
<rect key="frame" x="0.0" y="0.0" width="32" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="viF-Ee-7h0" customClass="MWMButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="32" height="32"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="MWMBlack"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<action selector="buttonTouchUpInside:" destination="-1" eventType="touchUpInside" id="aPG-4e-uSw"/>
|
||||
</connections>
|
||||
</button>
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="aMt-XV-9UK" userLabel="Spinner">
|
||||
<rect key="frame" x="0.0" y="0.0" width="32" height="32"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="viF-Ee-7h0" firstAttribute="top" secondItem="2DE-Qh-89K" secondAttribute="top" id="3gS-24-Olj"/>
|
||||
<constraint firstItem="aMt-XV-9UK" firstAttribute="width" relation="lessThanOrEqual" secondItem="vnA-dQ-QpI" secondAttribute="width" id="Bxj-4M-UlX"/>
|
||||
<constraint firstItem="aMt-XV-9UK" firstAttribute="centerX" secondItem="vnA-dQ-QpI" secondAttribute="centerX" id="EJm-Be-grG"/>
|
||||
<constraint firstItem="aMt-XV-9UK" firstAttribute="leading" secondItem="2DE-Qh-89K" secondAttribute="leading" priority="100" id="JK6-QX-JcI"/>
|
||||
<constraint firstAttribute="bottom" secondItem="aMt-XV-9UK" secondAttribute="bottom" priority="100" id="VFI-Yh-q1q"/>
|
||||
<constraint firstItem="aMt-XV-9UK" firstAttribute="centerY" secondItem="vnA-dQ-QpI" secondAttribute="centerY" id="eVP-mP-bGc"/>
|
||||
<constraint firstItem="aMt-XV-9UK" firstAttribute="height" relation="lessThanOrEqual" secondItem="vnA-dQ-QpI" secondAttribute="height" id="eWY-kL-sQD"/>
|
||||
<constraint firstAttribute="trailing" secondItem="viF-Ee-7h0" secondAttribute="trailing" id="fQT-G3-rJF"/>
|
||||
<constraint firstItem="aMt-XV-9UK" firstAttribute="top" secondItem="2DE-Qh-89K" secondAttribute="top" priority="100" id="fbs-bw-DIs"/>
|
||||
<constraint firstAttribute="bottom" secondItem="viF-Ee-7h0" secondAttribute="bottom" id="j4s-7V-lg9"/>
|
||||
<constraint firstAttribute="trailing" secondItem="aMt-XV-9UK" secondAttribute="trailing" priority="100" id="k01-wU-25n"/>
|
||||
<constraint firstItem="viF-Ee-7h0" firstAttribute="leading" secondItem="2DE-Qh-89K" secondAttribute="leading" id="sHS-iu-Url"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<viewLayoutGuide key="safeArea" id="vnA-dQ-QpI"/>
|
||||
<connections>
|
||||
<outlet property="button" destination="viF-Ee-7h0" id="0zP-Ye-sRs"/>
|
||||
<outlet property="owner" destination="-1" id="0n7-PI-5tO"/>
|
||||
<outlet property="spinner" destination="aMt-XV-9UK" id="bmp-bV-h3C"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="139" y="155"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
typedef NS_ENUM(NSInteger, MWMCircularProgressState) {
|
||||
MWMCircularProgressStateNormal,
|
||||
MWMCircularProgressStateSelected,
|
||||
MWMCircularProgressStateProgress,
|
||||
MWMCircularProgressStateSpinner,
|
||||
MWMCircularProgressStateFailed,
|
||||
MWMCircularProgressStateCompleted
|
||||
};
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#import "MWMButton.h"
|
||||
#import "MWMCircularProgress.h"
|
||||
|
||||
@interface MWMCircularProgressView : UIView
|
||||
|
||||
@property(nonatomic, readonly) BOOL animating;
|
||||
|
||||
@property(nonatomic) MWMCircularProgressState state;
|
||||
@property(nonatomic) BOOL isInvertColor;
|
||||
|
||||
- (nonnull instancetype)initWithFrame:(CGRect)frame
|
||||
__attribute__((unavailable("initWithFrame is not available")));
|
||||
- (nonnull instancetype)init __attribute__((unavailable("init is not available")));
|
||||
|
||||
- (void)setSpinnerColoring:(MWMImageColoring)coloring;
|
||||
- (void)setSpinnerBackgroundColor:(nonnull UIColor *)backgroundColor;
|
||||
- (void)setImageName:(nullable NSString *)imageName forState:(MWMCircularProgressState)state;
|
||||
- (void)setColor:(nonnull UIColor *)color forState:(MWMCircularProgressState)state;
|
||||
- (void)setColoring:(MWMButtonColoring)coloring forState:(MWMCircularProgressState)state;
|
||||
|
||||
- (void)animateFromValue:(CGFloat)fromValue toValue:(CGFloat)toValue;
|
||||
|
||||
- (void)updatePath:(CGFloat)progress;
|
||||
|
||||
- (UIView * _Nullable)buttonView;
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
#import "MWMCircularProgressView.h"
|
||||
#import "SwiftBridge.h"
|
||||
#import "UIImageView+Coloring.h"
|
||||
|
||||
static CGFloat const kLineWidth = 2.0;
|
||||
static NSString * const kAnimationKey = @"CircleAnimation";
|
||||
|
||||
static CGFloat angleWithProgress(CGFloat progress) { return 2.0 * M_PI * progress - M_PI_2; }
|
||||
|
||||
@interface MWMCircularProgressView ()
|
||||
|
||||
@property(nonatomic) CAShapeLayer * backgroundLayer;
|
||||
@property(nonatomic) CAShapeLayer * progressLayer;
|
||||
|
||||
@property(nonatomic) UIColor * spinnerBackgroundColor;
|
||||
@property(nonatomic, readonly) CGColorRef progressLayerColor;
|
||||
|
||||
@property(nonatomic) NSMutableDictionary * colors;
|
||||
@property(nonatomic) NSMutableDictionary<NSNumber *, NSNumber *> * buttonColoring;
|
||||
@property(nonatomic) NSMutableDictionary<NSNumber *, NSString *> * images;
|
||||
|
||||
@property(weak, nonatomic) IBOutlet MWMCircularProgress * owner;
|
||||
@property(weak, nonatomic) IBOutlet UIImageView * spinner;
|
||||
@property(weak, nonatomic) IBOutlet MWMButton * button;
|
||||
|
||||
@property(nonatomic) BOOL suspendRefreshProgress;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMCircularProgressView
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
self.suspendRefreshProgress = YES;
|
||||
[self setupColors];
|
||||
[self setupButtonColoring];
|
||||
self.images = [NSMutableDictionary dictionary];
|
||||
[self setupAnimationLayers];
|
||||
self.suspendRefreshProgress = NO;
|
||||
}
|
||||
|
||||
#pragma mark - Setup
|
||||
|
||||
- (void)setupColors
|
||||
{
|
||||
self.colors = [NSMutableDictionary dictionary];
|
||||
UIColor * progressColor = [_spinnerBackgroundColor isEqual:UIColor.clearColor]
|
||||
? UIColor.whiteColor
|
||||
: [UIColor linkBlue];
|
||||
UIColor * clearColor = UIColor.clearColor;
|
||||
[self setSpinnerColoring:MWMImageColoringGray];
|
||||
[self setColor:clearColor forState:MWMCircularProgressStateNormal];
|
||||
[self setColor:clearColor forState:MWMCircularProgressStateSelected];
|
||||
[self setColor:progressColor forState:MWMCircularProgressStateProgress];
|
||||
[self setColor:progressColor forState:MWMCircularProgressStateSpinner];
|
||||
[self setColor:clearColor forState:MWMCircularProgressStateFailed];
|
||||
[self setColor:clearColor forState:MWMCircularProgressStateCompleted];
|
||||
}
|
||||
|
||||
- (void)setupButtonColoring
|
||||
{
|
||||
self.buttonColoring = [NSMutableDictionary dictionary];
|
||||
[self setColoring:MWMButtonColoringBlack forState:MWMCircularProgressStateNormal];
|
||||
[self setColoring:MWMButtonColoringBlue forState:MWMCircularProgressStateSelected];
|
||||
[self setColoring:MWMButtonColoringBlue forState:MWMCircularProgressStateProgress];
|
||||
[self setColoring:MWMButtonColoringBlue forState:MWMCircularProgressStateSpinner];
|
||||
[self setColoring:MWMButtonColoringBlue forState:MWMCircularProgressStateFailed];
|
||||
[self setColoring:MWMButtonColoringBlue forState:MWMCircularProgressStateCompleted];
|
||||
}
|
||||
|
||||
- (void)applyTheme
|
||||
{
|
||||
[super applyTheme];
|
||||
self.suspendRefreshProgress = YES;
|
||||
[self setupColors];
|
||||
self.suspendRefreshProgress = NO;
|
||||
}
|
||||
|
||||
- (void)setupAnimationLayers
|
||||
{
|
||||
self.backgroundLayer = [CAShapeLayer layer];
|
||||
self.progressLayer = [CAShapeLayer layer];
|
||||
|
||||
[self refreshProgress];
|
||||
[self.layer addSublayer:self.backgroundLayer];
|
||||
[self.layer addSublayer:self.progressLayer];
|
||||
}
|
||||
|
||||
- (void)setSpinnerColoring:(MWMImageColoring)coloring { self.spinner.mwm_coloring = coloring; }
|
||||
- (void)setImageName:(nullable NSString *)imageName forState:(MWMCircularProgressState)state
|
||||
{
|
||||
self.images[@(state)] = imageName;
|
||||
[self refreshProgress];
|
||||
}
|
||||
|
||||
- (void)setColor:(UIColor *)color forState:(MWMCircularProgressState)state
|
||||
{
|
||||
self.colors[@(state)] = color;
|
||||
[self refreshProgress];
|
||||
}
|
||||
|
||||
- (void)setColoring:(MWMButtonColoring)coloring forState:(MWMCircularProgressState)state
|
||||
{
|
||||
self.buttonColoring[@(state)] = @(coloring);
|
||||
[self refreshProgress];
|
||||
}
|
||||
|
||||
#pragma mark - Progress
|
||||
|
||||
- (void)refreshProgress
|
||||
{
|
||||
if (self.suspendRefreshProgress)
|
||||
return;
|
||||
self.backgroundLayer.fillColor = self.progressLayer.fillColor = UIColor.clearColor.CGColor;
|
||||
self.backgroundLayer.lineWidth = self.progressLayer.lineWidth = kLineWidth;
|
||||
self.backgroundLayer.strokeColor = self.spinnerBackgroundColor.CGColor;
|
||||
[self updateBackgroundPath];
|
||||
self.progressLayer.strokeColor = self.progressLayerColor;
|
||||
NSString * imageName = self.images[@(self.state)];
|
||||
if (imageName)
|
||||
{
|
||||
[self.button setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];
|
||||
UIImage *hl = [UIImage imageNamed:[imageName stringByAppendingString:@"_highlighted"]];
|
||||
if (hl)
|
||||
[self.button setImage:hl forState:UIControlStateHighlighted];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self.button setImage:nil forState:UIControlStateNormal];
|
||||
[self.button setImage:nil forState:UIControlStateHighlighted];
|
||||
}
|
||||
|
||||
self.button.coloring = (MWMButtonColoring)self.buttonColoring[@(self.state)].unsignedIntegerValue;
|
||||
}
|
||||
|
||||
- (void)updatePath:(CGFloat)progress
|
||||
{
|
||||
[self updateBackgroundPath];
|
||||
if (progress > 0.0)
|
||||
{
|
||||
self.state =
|
||||
progress < 1.0 ? MWMCircularProgressStateProgress : MWMCircularProgressStateCompleted;
|
||||
[self stopSpinner];
|
||||
}
|
||||
self.progressLayer.path = [self pathWithProgress:progress].CGPath;
|
||||
}
|
||||
|
||||
- (void)updateBackgroundPath
|
||||
{
|
||||
self.backgroundLayer.path = [self pathWithProgress:1.0].CGPath;
|
||||
}
|
||||
|
||||
- (UIBezierPath *)pathWithProgress:(CGFloat)progress
|
||||
{
|
||||
CGPoint center = CGPointMake(self.width / 2.0, self.height / 2.0);
|
||||
CGFloat radius = MIN(center.x, center.y) - kLineWidth;
|
||||
UIBezierPath * path = [UIBezierPath bezierPathWithArcCenter:center
|
||||
radius:radius
|
||||
startAngle:angleWithProgress(0.0)
|
||||
endAngle:angleWithProgress(progress)
|
||||
clockwise:YES];
|
||||
return path;
|
||||
}
|
||||
#pragma mark - Spinner
|
||||
|
||||
- (void)startSpinner
|
||||
{
|
||||
if (self.spinner.hidden)
|
||||
{
|
||||
self.spinner.hidden = NO;
|
||||
self.backgroundLayer.hidden = self.progressLayer.hidden = YES;
|
||||
}
|
||||
NSString * postfix = ([UIColor isNightMode] && !self.isInvertColor) ||
|
||||
(![UIColor isNightMode] && self.isInvertColor) ||
|
||||
_spinnerBackgroundColor
|
||||
? @"dark"
|
||||
: @"light";
|
||||
UIImage * image = [UIImage imageNamed:[NSString stringWithFormat:@"Spinner_%@", postfix]];
|
||||
self.spinner.image = image;
|
||||
[self.spinner startRotation:1];
|
||||
}
|
||||
|
||||
- (void)stopSpinner
|
||||
{
|
||||
if (self.spinner.hidden)
|
||||
return;
|
||||
self.spinner.hidden = YES;
|
||||
self.backgroundLayer.hidden = self.progressLayer.hidden = NO;
|
||||
[self.spinner stopRotation];
|
||||
}
|
||||
|
||||
#pragma mark - Animation
|
||||
|
||||
- (void)animateFromValue:(CGFloat)fromValue toValue:(CGFloat)toValue
|
||||
{
|
||||
[self updatePath:toValue];
|
||||
CABasicAnimation * animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
|
||||
animation.duration = kDefaultAnimationDuration;
|
||||
animation.repeatCount = 1;
|
||||
animation.fromValue = @(fromValue / toValue);
|
||||
animation.toValue = @1;
|
||||
animation.timingFunction =
|
||||
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
|
||||
animation.delegate = self.owner;
|
||||
[self.progressLayer addAnimation:animation forKey:kAnimationKey];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (UIView * _Nullable)buttonView
|
||||
{
|
||||
return self.button;
|
||||
}
|
||||
|
||||
- (void)setState:(MWMCircularProgressState)state
|
||||
{
|
||||
if (state == MWMCircularProgressStateSpinner)
|
||||
[self startSpinner];
|
||||
else if (_state == MWMCircularProgressStateSpinner)
|
||||
[self stopSpinner];
|
||||
if (_state == state)
|
||||
return;
|
||||
_state = state;
|
||||
[self refreshProgress];
|
||||
}
|
||||
|
||||
- (UIColor *)spinnerBackgroundColor
|
||||
{
|
||||
if (_spinnerBackgroundColor)
|
||||
return _spinnerBackgroundColor;
|
||||
switch (self.state)
|
||||
{
|
||||
case MWMCircularProgressStateProgress: return [UIColor pressBackground];
|
||||
default: return UIColor.clearColor;
|
||||
}
|
||||
}
|
||||
|
||||
- (CGColorRef)progressLayerColor
|
||||
{
|
||||
UIColor * color = self.colors[@(self.state)];
|
||||
return color.CGColor;
|
||||
}
|
||||
|
||||
- (void)setFrame:(CGRect)frame
|
||||
{
|
||||
BOOL needrefreshProgress = !CGRectEqualToRect(self.frame, frame);
|
||||
super.frame = frame;
|
||||
if (needrefreshProgress)
|
||||
[self refreshProgress];
|
||||
}
|
||||
|
||||
- (BOOL)animating { return [self.progressLayer animationForKey:kAnimationKey] != nil; }
|
||||
- (void)setSuspendRefreshProgress:(BOOL)suspendRefreshProgress
|
||||
{
|
||||
_suspendRefreshProgress = suspendRefreshProgress;
|
||||
if (!suspendRefreshProgress)
|
||||
[self refreshProgress];
|
||||
}
|
||||
|
||||
@end
|
||||
Loading…
Add table
Add a link
Reference in a new issue