From 6e816ead8bb07fa438366e3782196dfebccfe177 Mon Sep 17 00:00:00 2001 From: Alexey Chechetkin Date: Fri, 21 Aug 2015 01:16:36 +0300 Subject: [PATCH] IconCloud was improved to add new icon type. StatusListController was refactored to support new vector IconCloud icons, added new animations to all status items. --- .../project.pbxproj | 14 +- .../Base.lproj/controllers.storyboard | 24 +- TransmissionRPCClient/IconCloud.h | 6 + TransmissionRPCClient/IconCloud.m | 309 ++++++++++++++++-- TransmissionRPCClient/Info.plist | 2 +- TransmissionRPCClient/StatusCategories.m | 14 +- TransmissionRPCClient/StatusCategory.h | 13 +- TransmissionRPCClient/StatusCategory.m | 8 +- TransmissionRPCClient/StatusListCell.h | 3 +- TransmissionRPCClient/StatusListController.m | 16 +- TransmissionRPCClient/TRInfos.m | 12 + 11 files changed, 348 insertions(+), 73 deletions(-) diff --git a/TransmissionRPCClient.xcodeproj/project.pbxproj b/TransmissionRPCClient.xcodeproj/project.pbxproj index 7b85da2..cab4392 100644 --- a/TransmissionRPCClient.xcodeproj/project.pbxproj +++ b/TransmissionRPCClient.xcodeproj/project.pbxproj @@ -52,6 +52,7 @@ 2CF861441B77BD0D00E47F53 /* TorrentTitleSectionHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CF861431B77BD0D00E47F53 /* TorrentTitleSectionHeaderView.m */; }; 2CF861481B77C0C300E47F53 /* icons.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CF861471B77C0C300E47F53 /* icons.xcassets */; }; 2CF8C7651B4302F7005A7DD6 /* PeerListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CF8C7641B4302F7005A7DD6 /* PeerListCell.m */; }; + 2CF8DEEB1B8624D000790238 /* IconCloud.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CF8DEEA1B8624D000790238 /* IconCloud.m */; }; 2CF8EF781B61736100EB8D5D /* TrackerListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CF8EF771B61736100EB8D5D /* TrackerListCell.m */; }; 2CF8EF7B1B6179AE00EB8D5D /* TrackerStat.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CF8EF7A1B6179AE00EB8D5D /* TrackerStat.m */; }; 2CF911961B41B605003D0753 /* ChooseServerToAddTorrentController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CF911951B41B605003D0753 /* ChooseServerToAddTorrentController.m */; }; @@ -64,7 +65,6 @@ 2CF971AB1B790379008EE25D /* GeoIpConnector.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CF971AA1B790379008EE25D /* GeoIpConnector.m */; }; 2CF971AF1B790B23008EE25D /* IPGeoInfoController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CF971AE1B790B23008EE25D /* IPGeoInfoController.m */; }; 2CF9C4C91B84E36900DA4487 /* IconHalfCloud.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CF9C4C81B84E36900DA4487 /* IconHalfCloud.m */; }; - 2CF9C4CC1B84EAC100DA4487 /* IconCloud.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CF9C4CB1B84EAC100DA4487 /* IconCloud.m */; }; 2CF9C4CF1B84EE3B00DA4487 /* IconFS.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CF9C4CE1B84EE3B00DA4487 /* IconFS.m */; }; 2CFA5E101B43237400262C36 /* TRFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CFA5E0F1B43237400262C36 /* TRFileInfo.m */; }; 2CFA5E141B432ABF00262C36 /* FileListController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CFA5E131B432ABF00262C36 /* FileListController.m */; }; @@ -175,6 +175,8 @@ 2CF861471B77C0C300E47F53 /* icons.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = icons.xcassets; sourceTree = ""; }; 2CF8C7631B4302F7005A7DD6 /* PeerListCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PeerListCell.h; sourceTree = ""; }; 2CF8C7641B4302F7005A7DD6 /* PeerListCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PeerListCell.m; sourceTree = ""; }; + 2CF8DEE91B8624D000790238 /* IconCloud.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IconCloud.h; sourceTree = ""; }; + 2CF8DEEA1B8624D000790238 /* IconCloud.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IconCloud.m; sourceTree = ""; }; 2CF8EF761B61736100EB8D5D /* TrackerListCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackerListCell.h; sourceTree = ""; }; 2CF8EF771B61736100EB8D5D /* TrackerListCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TrackerListCell.m; sourceTree = ""; }; 2CF8EF791B6179AE00EB8D5D /* TrackerStat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackerStat.h; sourceTree = ""; }; @@ -194,8 +196,6 @@ 2CF971AE1B790B23008EE25D /* IPGeoInfoController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IPGeoInfoController.m; sourceTree = ""; }; 2CF9C4C71B84E36900DA4487 /* IconHalfCloud.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IconHalfCloud.h; sourceTree = ""; }; 2CF9C4C81B84E36900DA4487 /* IconHalfCloud.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IconHalfCloud.m; sourceTree = ""; }; - 2CF9C4CA1B84EAC100DA4487 /* IconCloud.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IconCloud.h; sourceTree = ""; }; - 2CF9C4CB1B84EAC100DA4487 /* IconCloud.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IconCloud.m; sourceTree = ""; }; 2CF9C4CD1B84EE3B00DA4487 /* IconFS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IconFS.h; sourceTree = ""; }; 2CF9C4CE1B84EE3B00DA4487 /* IconFS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IconFS.m; sourceTree = ""; }; 2CFA5E0E1B43237400262C36 /* TRFileInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TRFileInfo.h; sourceTree = ""; }; @@ -398,8 +398,8 @@ 2CB651CC1B3DCC91005C823C /* Torrent list controller */ = { isa = PBXGroup; children = ( - 2CF9C4CA1B84EAC100DA4487 /* IconCloud.h */, - 2CF9C4CB1B84EAC100DA4487 /* IconCloud.m */, + 2CF8DEE91B8624D000790238 /* IconCloud.h */, + 2CF8DEEA1B8624D000790238 /* IconCloud.m */, 2CB651CD1B3DCCBE005C823C /* TorrentListController.h */, 2CB651CE1B3DCCBE005C823C /* TorrentListController.m */, 2CB651D01B3DCDD4005C823C /* TorrentListCell.h */, @@ -762,7 +762,6 @@ 2CF9C4CF1B84EE3B00DA4487 /* IconFS.m in Sources */, 2CF91D111B3C8B3B0093637A /* StatusListController.m in Sources */, 2C6D18BD1B3B477E002666C6 /* ServerListItemCell.m in Sources */, - 2CF9C4CC1B84EAC100DA4487 /* IconCloud.m in Sources */, 2CF690A21B4BE74A00B2F830 /* HeaderViewDURates.m in Sources */, 2C039F3B1B52D33C00233534 /* StatusCategory.m in Sources */, 2C4673151B3D91BA00CBD6B1 /* RPCConnector.m in Sources */, @@ -772,6 +771,7 @@ 2CF7F3211B6EBF2B007EEBF6 /* PeerStatCell.m in Sources */, 2C5810DF1B39A5E50069020D /* AppDelegate.m in Sources */, 2C6668341B5BB1D3004B6FA4 /* Bencoding.m in Sources */, + 2CF8DEEB1B8624D000790238 /* IconCloud.m in Sources */, 2CF730091B657D25007D5354 /* ScheduleAltLimitsController.m in Sources */, 2C0E34A81B4006EB004303AB /* TRInfos.m in Sources */, 2CF9C4C91B84E36900DA4487 /* IconHalfCloud.m in Sources */, @@ -966,6 +966,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; @@ -981,6 +982,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; diff --git a/TransmissionRPCClient/Base.lproj/controllers.storyboard b/TransmissionRPCClient/Base.lproj/controllers.storyboard index 25c15c0..c735f8d 100644 --- a/TransmissionRPCClient/Base.lproj/controllers.storyboard +++ b/TransmissionRPCClient/Base.lproj/controllers.storyboard @@ -482,13 +482,6 @@ - - - - - - - + + + + + + + - + - - + + - + diff --git a/TransmissionRPCClient/IconCloud.h b/TransmissionRPCClient/IconCloud.h index a202aba..64d6678 100644 --- a/TransmissionRPCClient/IconCloud.h +++ b/TransmissionRPCClient/IconCloud.h @@ -15,6 +15,8 @@ typedef NS_ENUM(int, IconCloudType) IconCloudTypeCheck, IconCloudTypeStop, IconCloudTypeError, + IconCloudTypeActive, + IconCloudTypeAll, IconCloudTypeNone }; @@ -25,6 +27,7 @@ typedef NS_ENUM(int, IconCloudType) @property(nonatomic,readonly) BOOL isCheckAnimationInProgress; @property(nonatomic,readonly) BOOL isUploadAnimationInProgress; @property(nonatomic,readonly) BOOL isDownloadAnimationInProgress; +@property(nonatomic,readonly) BOOL isActivityAnimationInProgress; - (void)playCheckAnimation; - (void)stopCheckAnimation; @@ -35,4 +38,7 @@ typedef NS_ENUM(int, IconCloudType) - (void)playDownloadAnimation; - (void)stopDownloadAnimation; +- (void)playActivityAnimation; +- (void)stopActivityAnimation; + @end diff --git a/TransmissionRPCClient/IconCloud.m b/TransmissionRPCClient/IconCloud.m index 428bb4d..3545b66 100644 --- a/TransmissionRPCClient/IconCloud.m +++ b/TransmissionRPCClient/IconCloud.m @@ -11,13 +11,19 @@ @implementation IconCloud { + /// bunch of layers CAShapeLayer *_layerCloud; CAShapeLayer *_layerArrowUp; CAShapeLayer *_layerArrowDown; CAShapeLayer *_layerCircleArrows; CAShapeLayer *_layerStopButton; CAShapeLayer *_layerCrossButton; + CAShapeLayer *_layerLittleArrowUp; + CAShapeLayer *_layerLittleArrowDown; + CAShapeLayer *_layerClouds; + CAShapeLayer *_layerArrows; + /// main layer frame CGRect _frame; } @@ -39,7 +45,7 @@ - (void)setupValues { [self createLayers]; - [self setLayersStrokeColor]; + [self setLayersColors]; self.iconType = IconCloudTypeNone; } @@ -111,7 +117,7 @@ - (BOOL)isUploadAnimationInProgress { - return [_layerArrowUp animationForKey:@"uploadAnimation"]; + return [_layerArrowUp animationForKey:@"uploadAnimation"] != nil; } - (void)stopUploadAnimation @@ -158,61 +164,181 @@ - (BOOL)isDownloadAnimationInProgress { - return [_layerArrowDown animationForKey:@"downloadAnimation"]; + return [_layerArrowDown animationForKey:@"downloadAnimation"] != nil; +} + +- (void)playActivityAnimation +{ + if( self.isActivityAnimationInProgress ) + return; + + CABasicAnimation *a0 = [CABasicAnimation animationWithKeyPath:@"position.y"]; + a0.beginTime = 0; + a0.duration = 1.5; + a0.autoreverses = YES; + a0.repeatCount = HUGE_VALF; + a0.byValue = @(-3); + [_layerLittleArrowUp addAnimation:a0 forKey:@"activityAnimationUp"]; + + CABasicAnimation *a1 = [CABasicAnimation animationWithKeyPath:@"position.y"]; + a1.beginTime = 0; + a1.duration = 1.5; + a1.autoreverses = YES; + a1.repeatCount = HUGE_VALF; + a1.byValue = @(3); + [_layerLittleArrowDown addAnimation:a1 forKey:@"activityAnimationDown"]; + + [self animateScale]; +} + +- (void)stopActivityAnimation +{ + [_layerLittleArrowDown removeAllAnimations]; + [_layerLittleArrowUp removeAllAnimations]; +} + +- (BOOL)isActivityAnimationInProgress +{ + return [_layerLittleArrowUp animationForKey:@"activityAnimationUp"] != nil; } - (void)createLayers { + _frame = self.frame; + _frame.origin = CGPointZero; + + ///////////////////////////////////// + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + ///////////////////////////////////// + + + /// CREATE _layerCloud = [CAShapeLayer layer]; + _layerArrowUp = [CAShapeLayer layer]; _layerArrowDown = [CAShapeLayer layer]; + _layerCircleArrows = [CAShapeLayer layer]; _layerStopButton = [CAShapeLayer layer]; _layerCrossButton = [CAShapeLayer layer]; - _layerCrossButton.contentsScale = _layerCloud.contentsScale = _layerArrowUp.contentsScale = _layerArrowDown.contentsScale = _layerCircleArrows.contentsScale = _layerStopButton.contentsScale = [UIScreen mainScreen].scale; + _layerLittleArrowDown = [CAShapeLayer layer]; + _layerLittleArrowUp = [CAShapeLayer layer]; - _frame = self.frame; - _frame.origin = CGPointZero; + _layerClouds = [CAShapeLayer layer]; + _layerArrows = [CAShapeLayer layer]; - _layerCloud.frame = _frame; + /// SCALE + _layerCrossButton.contentsScale = + _layerCloud.contentsScale = + _layerArrowUp.contentsScale = + _layerArrowDown.contentsScale = + _layerCircleArrows.contentsScale = + _layerStopButton.contentsScale = + _layerLittleArrowDown.contentsScale = + _layerLittleArrowUp.contentsScale = + _layerClouds.contentsScale = + _layerArrows.contentsScale = + [UIScreen mainScreen].scale; - _layerCrossButton.fillColor = _layerCloud.fillColor = _layerArrowUp.fillColor = _layerArrowDown.fillColor = _layerCircleArrows.fillColor = _layerStopButton.fillColor = [UIColor clearColor].CGColor; - _layerCrossButton.lineWidth = _layerArrowUp.lineWidth = _layerArrowDown.lineWidth = _layerCircleArrows.lineWidth = _layerStopButton.lineWidth = 1.5; + /// LINE WIDTH + _layerCrossButton.lineWidth = + _layerArrowUp.lineWidth = + _layerArrowDown.lineWidth = + _layerCircleArrows.lineWidth = + _layerStopButton.lineWidth = + _layerLittleArrowUp.lineWidth = + _layerLittleArrowDown.lineWidth = + _layerArrows.lineWidth = + 1.5; - _layerCloud.lineWidth = 2.0; + _layerCloud.lineWidth = + _layerClouds.lineWidth = + 2.0; - _layerCrossButton.lineCap = _layerCloud.lineCap = _layerArrowDown.lineCap = _layerArrowUp.lineCap = _layerStopButton.lineCap = kCALineCapRound; + /// LINE CAPS + _layerCrossButton.lineCap = + _layerCloud.lineCap = + _layerArrowDown.lineCap = + _layerArrowUp.lineCap = + _layerStopButton.lineCap = + _layerLittleArrowUp.lineCap = + _layerLittleArrowDown.lineCap = + _layerArrows.lineCap = + _layerClouds.lineCap = + kCALineCapRound; - _layerCloud.path = self.cloudPath; - - _layerCircleArrows.path = self.circleArrowsPath; _layerCircleArrows.lineCap = kCALineCapSquare; - + + /// SET PATHS + _layerCloud.path = self.cloudPath; + _layerCircleArrows.path = self.circleArrowsPath; _layerArrowDown.path = self.arrowDownPath; _layerArrowUp.path = self.arrowUpPath; _layerStopButton.path = self.stopButtonPath; _layerCrossButton.path = self.crossButtonPath; + _layerLittleArrowDown.path = self.littleArrowDownPath; + _layerLittleArrowUp.path = self.littleArrowUpPath; + _layerArrows.path = self.arrowsPath; + _layerClouds.path = self.cloudsPath; + /// ADD TO VIEW [self.layer addSublayer:_layerCloud]; + [self.layer addSublayer:_layerClouds]; + [self.layer addSublayer:_layerArrows]; [_layerCloud addSublayer:_layerCircleArrows]; [_layerCloud addSublayer:_layerArrowDown]; [_layerCloud addSublayer:_layerArrowUp]; [_layerCloud addSublayer:_layerStopButton]; [_layerCloud addSublayer:_layerCrossButton]; + + [_layerCloud addSublayer:_layerLittleArrowDown]; + [_layerCloud addSublayer:_layerLittleArrowUp]; + + ////////////////////// + [CATransaction commit]; } - (void)setTintColor:(UIColor *)tintColor { [super setTintColor:tintColor]; - [self setLayersStrokeColor]; + + [self setLayersColors]; } -- (void)setLayersStrokeColor +- (void)setLayersColors { - _layerCloud.strokeColor = _layerArrowUp.strokeColor = _layerArrowDown.strokeColor = _layerCircleArrows.strokeColor = _layerStopButton.strokeColor = _layerCrossButton.strokeColor = self.tintColor.CGColor; + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + + _layerCloud.strokeColor = + _layerArrowUp.strokeColor = + _layerArrowDown.strokeColor = + _layerCircleArrows.strokeColor = + _layerStopButton.strokeColor = + _layerCrossButton.strokeColor = + _layerLittleArrowUp.strokeColor = + _layerLittleArrowDown.strokeColor = + _layerClouds.strokeColor = + _layerArrows.strokeColor = + self.tintColor.CGColor; + + _layerCrossButton.fillColor = + _layerCloud.fillColor = + _layerArrowUp.fillColor = + _layerArrowDown.fillColor = + _layerCircleArrows.fillColor = + _layerStopButton.fillColor = + _layerLittleArrowUp.fillColor = + _layerLittleArrowDown.fillColor = + _layerArrows.fillColor = + _layerClouds.fillColor = + nil; + + [CATransaction commit]; } - (void)setIconType:(IconCloudType)iconType @@ -225,15 +351,24 @@ [_layerArrowUp removeAllAnimations]; [_layerArrowDown removeAllAnimations]; [_layerCircleArrows removeAllAnimations]; + [_layerLittleArrowDown removeAllAnimations]; + [_layerLittleArrowUp removeAllAnimations]; [CATransaction begin]; - [CATransaction setAnimationDuration:0.0]; + [CATransaction setDisableActions:YES]; - _layerCircleArrows.hidden = YES; - _layerArrowDown.hidden = YES; - _layerArrowUp.hidden = YES; - _layerStopButton.hidden = YES; - _layerCrossButton.hidden = YES; + _layerCloud.hidden = NO; + + _layerCircleArrows.hidden = + _layerArrowDown.hidden = + _layerArrowUp.hidden = + _layerStopButton.hidden = + _layerCrossButton.hidden = + _layerLittleArrowUp.hidden = + _layerLittleArrowDown.hidden = + _layerClouds.hidden = + _layerArrows.hidden = + YES; switch (iconType) { @@ -256,6 +391,17 @@ case IconCloudTypeError: _layerCrossButton.hidden = NO; break; + + case IconCloudTypeActive: + _layerLittleArrowDown.hidden = NO; + _layerLittleArrowUp.hidden = NO; + break; + + case IconCloudTypeAll: + _layerArrows.hidden = NO; + _layerClouds.hidden = NO; + _layerCloud.hidden = YES; + break; default: break; @@ -264,11 +410,22 @@ [CATransaction commit]; } +- (CGRect)frame2 +{ + CGFloat w = _frame.size.width; + CGFloat h = _frame.size.height; + + CGRect _frame2 = CGRectMake(floor(w * 0.30488 + 0.5),floor(h * 0.50311 + 0.5), floor(w * 0.71341 + 0.5) - floor(w * 0.30488 + 0.5), floor(h * 0.86335 + 0.5) - floor(h * 0.50311 + 0.5)); + + return _frame2; +} + - (CGPathRef)cloudPath { //static CGPathRef path = NULL; + _layerCloud.frame = _frame; if( path == NULL ) { CGFloat w = _frame.size.width; @@ -295,22 +452,13 @@ [cloudPath addCurveToPoint: CGPointMake(0.80913 * w, 0.71086 * h) controlPoint1: CGPointMake(0.89772 * w, 0.69338 * h) controlPoint2: CGPointMake(0.85689 * w, 0.71086 * h)]; [cloudPath addLineToPoint: CGPointMake(0.76976 * w, 0.71086 * h)]; + path = cloudPath.CGPath; } return path; } -- (CGRect)frame2 -{ - CGFloat w = _frame.size.width; - CGFloat h = _frame.size.height; - - CGRect _frame2 = CGRectMake(floor(w * 0.30488 + 0.5),floor(h * 0.50311 + 0.5), floor(w * 0.71341 + 0.5) - floor(w * 0.30488 + 0.5), floor(h * 0.86335 + 0.5) - floor(h * 0.50311 + 0.5)); - - return _frame2; -} - - (CGPathRef)circleArrowsPath { //static @@ -453,4 +601,97 @@ return path; } +- (CGPathRef)littleArrowUpPath +{ + CGFloat w = _frame.size.width; + CGFloat h = _frame.size.height; + + UIBezierPath* arrUpPath = UIBezierPath.bezierPath; + [arrUpPath moveToPoint: CGPointMake( 0.45200 * w, 0.50074 * h)]; + [arrUpPath addLineToPoint: CGPointMake( 0.45200 * w, 0.78513 * h)]; + [arrUpPath moveToPoint: CGPointMake( 0.35745 * w, 0.59071 * h)]; + [arrUpPath addLineToPoint: CGPointMake( 0.45200 * w, 0.49405 * h)]; + [arrUpPath addLineToPoint: CGPointMake( 0.54655 * w, 0.59071 * h)]; + + _layerLittleArrowUp.frame = _frame; + return arrUpPath.CGPath; +} + +- (CGPathRef)littleArrowDownPath +{ + CGFloat w = _frame.size.width; + CGFloat h = _frame.size.height; + + UIBezierPath* arrDownPath = UIBezierPath.bezierPath; + [arrDownPath moveToPoint: CGPointMake( 0.61200 * w, 0.87026 * h)]; + [arrDownPath addLineToPoint: CGPointMake( 0.61200 * w, 0.58587 * h)]; + [arrDownPath moveToPoint: CGPointMake( 0.70655 * w, 0.78030 * h)]; + [arrDownPath addLineToPoint: CGPointMake( 0.61200 * w, 0.87695 * h)]; + [arrDownPath addLineToPoint: CGPointMake( 0.51745 * w, 0.78030 * h)]; + + _layerLittleArrowDown.frame = _frame; + return arrDownPath.CGPath; +} + +- (CGPathRef)cloudsPath +{ + CGFloat w = _frame.size.width; + CGFloat h = _frame.size.height; + + UIBezierPath* cloudsPath = UIBezierPath.bezierPath; + [cloudsPath moveToPoint: CGPointMake(0.44914 * w, 0.74233 * h)]; + [cloudsPath addLineToPoint: CGPointMake(0.33726 * w, 0.74233 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.23247 * w, 0.69888 * h) controlPoint1: CGPointMake(0.29627 * w, 0.74233 * h) controlPoint2: CGPointMake(0.26144 * w, 0.72785 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.18901 * w, 0.59408 * h) controlPoint1: CGPointMake(0.20350 * w, 0.66990 * h) controlPoint2: CGPointMake(0.18901 * w, 0.63507 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.23247 * w, 0.48929 * h) controlPoint1: CGPointMake(0.18901 * w, 0.55309 * h) controlPoint2: CGPointMake(0.20350 * w, 0.51826 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.33726 * w, 0.44583 * h) controlPoint1: CGPointMake(0.26144 * w, 0.46032 * h) controlPoint2: CGPointMake(0.29627 * w, 0.44583 * h)]; + [cloudsPath addLineToPoint: CGPointMake(0.33726 * w, 0.43566 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.39428 * w, 0.29851 * h) controlPoint1: CGPointMake(0.33757 * w, 0.38203 * h) controlPoint2: CGPointMake(0.35668 * w, 0.33642 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.53082 * w, 0.24149 * h) controlPoint1: CGPointMake(0.43219 * w, 0.26059 * h) controlPoint2: CGPointMake(0.47781 * w, 0.24149 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.64918 * w, 0.28032 * h) controlPoint1: CGPointMake(0.57551 * w, 0.24149 * h) controlPoint2: CGPointMake(0.61496 * w, 0.25443 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.71883 * w, 0.38234 * h) controlPoint1: CGPointMake(0.68339 * w, 0.30621 * h) controlPoint2: CGPointMake(0.70681 * w, 0.34042 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.78202 * w, 0.37155 * h) controlPoint1: CGPointMake(0.74041 * w, 0.37525 * h) controlPoint2: CGPointMake(0.76167 * w, 0.37155 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.91208 * w, 0.42580 * h) controlPoint1: CGPointMake(0.83256 * w, 0.37155 * h) controlPoint2: CGPointMake(0.87602 * w, 0.38974 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.96633 * w, 0.55679 * h) controlPoint1: CGPointMake(0.94814 * w, 0.46186 * h) controlPoint2: CGPointMake(0.96633 * w, 0.50562 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.91208 * w, 0.68778 * h) controlPoint1: CGPointMake(0.96633 * w, 0.60795 * h) controlPoint2: CGPointMake(0.94814 * w, 0.65172 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.78202 * w, 0.74202 * h) controlPoint1: CGPointMake(0.87602 * w, 0.72384 * h) controlPoint2: CGPointMake(0.83256 * w, 0.74202 * h)]; + [cloudsPath addLineToPoint: CGPointMake(0.69078 * w, 0.74202 * h)]; + [cloudsPath moveToPoint: CGPointMake(0.45932 * w, 0.22762 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.44082 * w, 0.21128 * h) controlPoint1: CGPointMake(0.45346 * w, 0.22176 * h) controlPoint2: CGPointMake(0.44760 * w, 0.21621 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.33665 * w, 0.17707 * h) controlPoint1: CGPointMake(0.41062 * w, 0.18847 * h) controlPoint2: CGPointMake(0.37579 * w, 0.17707 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.21644 * w, 0.22731 * h) controlPoint1: CGPointMake(0.28980 * w, 0.17707 * h) controlPoint2: CGPointMake(0.24973 * w, 0.19371 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.16620 * w, 0.34905 * h) controlPoint1: CGPointMake(0.18316 * w, 0.26090 * h) controlPoint2: CGPointMake(0.16620 * w, 0.30128 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.16929 * w, 0.35707 * h) controlPoint1: CGPointMake(0.16620 * w, 0.35306 * h) controlPoint2: CGPointMake(0.16744 * w, 0.35552 * h)]; + [cloudsPath addLineToPoint: CGPointMake(0.16620 * w, 0.35707 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.07374 * w, 0.39528 * h) controlPoint1: CGPointMake(0.13014 * w, 0.35707 * h) controlPoint2: CGPointMake(0.09932 * w, 0.36970 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.03552 * w, 0.48775 * h) controlPoint1: CGPointMake(0.04816 * w, 0.42087 * h) controlPoint2: CGPointMake(0.03552 * w, 0.45169 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.07374 * w, 0.58021 * h) controlPoint1: CGPointMake(0.03552 * w, 0.52381 * h) controlPoint2: CGPointMake(0.04816 * w, 0.55463 * h)]; + [cloudsPath addCurveToPoint: CGPointMake(0.16620 * w, 0.61843 * h) controlPoint1: CGPointMake(0.09932 * w, 0.60579 * h) controlPoint2: CGPointMake(0.12984 * w, 0.61843 * h)]; + [cloudsPath addLineToPoint: CGPointMake(0.16929 * w, 0.61843 * h)]; + + _layerClouds.frame = _frame; + return cloudsPath.CGPath; +} + +- (CGPathRef)arrowsPath +{ + CGFloat w = _frame.size.width; + CGFloat h = _frame.size.height; + + UIBezierPath* arrowsPath = UIBezierPath.bezierPath; + [arrowsPath moveToPoint: CGPointMake(0.62298 * w, 0.58977 * h)]; + [arrowsPath addLineToPoint: CGPointMake(0.62298 * w, 0.77346 * h)]; + [arrowsPath moveToPoint: CGPointMake(0.56103 * w, 0.64788 * h)]; + [arrowsPath addLineToPoint: CGPointMake(0.62298 * w, 0.58545 * h)]; + [arrowsPath addLineToPoint: CGPointMake(0.68493 * w, 0.64788 * h)]; + [arrowsPath moveToPoint: CGPointMake(0.52065 * w, 0.86469 * h)]; + [arrowsPath addLineToPoint: CGPointMake(0.52065 * w, 0.68100 * h)]; + [arrowsPath moveToPoint: CGPointMake(0.58260 * w, 0.80658 * h)]; + [arrowsPath addLineToPoint: CGPointMake(0.52065 * w, 0.86901 * h)]; + [arrowsPath addLineToPoint: CGPointMake(0.45870 * w, 0.80658 * h)]; + + _layerArrows.frame = _frame; + return arrowsPath.CGPath; +} + @end diff --git a/TransmissionRPCClient/Info.plist b/TransmissionRPCClient/Info.plist index c1e54ff..a579171 100644 --- a/TransmissionRPCClient/Info.plist +++ b/TransmissionRPCClient/Info.plist @@ -56,7 +56,7 @@ CFBundleVersion - 383 + 385 LSRequiresIPhoneOS UIBackgroundModes diff --git a/TransmissionRPCClient/StatusCategories.m b/TransmissionRPCClient/StatusCategories.m index 8e9410a..39e8958 100644 --- a/TransmissionRPCClient/StatusCategories.m +++ b/TransmissionRPCClient/StatusCategories.m @@ -52,7 +52,7 @@ static NSString* TITLE_ERROR; StatusCategory *c; // Fill categories - c = [StatusCategory categoryWithTitle:TITLE_ALL isAlwaysVisible:YES icon:[UIImage iconAll]]; + c = [StatusCategory categoryWithTitle:TITLE_ALL isAlwaysVisible:YES iconType:IconCloudTypeAll]; [c addItemWithTitle:TITLE_DOWN filter: TRINFOS_KEY_DOWNTORRENTS]; [c addItemWithTitle:TITLE_SEED filter: TRINFOS_KEY_SEEDTORRENTS]; [c addItemWithTitle:TITLE_STOP filter: TRINFOS_KEY_STOPTORRENTS]; @@ -61,35 +61,35 @@ static NSString* TITLE_ERROR; c.emptyTitle = NSLocalizedString(@"There are no torrents to show", @"Category ALL emtpy title"); [_items addObject:c]; - c = [StatusCategory categoryWithTitle:TITLE_ACTIVE isAlwaysVisible:YES icon:[UIImage iconActive]]; + c = [StatusCategory categoryWithTitle:TITLE_ACTIVE isAlwaysVisible:YES iconType:IconCloudTypeActive]; [c addItemWithTitle:TITLE_ACTIVE filter:TRINFOS_KEY_ACTIVETORRENTS]; c.emptyTitle = NSLocalizedString(@"There are no active torrents to show", @"Category empty title"); [_items addObject:c]; - c = [StatusCategory categoryWithTitle:TITLE_DOWN isAlwaysVisible:NO icon:[UIImage iconDownload]]; + c = [StatusCategory categoryWithTitle:TITLE_DOWN isAlwaysVisible:NO iconType:IconCloudTypeDownload]; [c addItemWithTitle:TITLE_DOWN filter: TRINFOS_KEY_DOWNTORRENTS]; c.emptyTitle = NSLocalizedString(@"There are no downloading torrents to show", @"Category empty title"); [_items addObject:c]; - c = [StatusCategory categoryWithTitle:TITLE_SEED isAlwaysVisible:NO icon:[UIImage iconUpload]]; + c = [StatusCategory categoryWithTitle:TITLE_SEED isAlwaysVisible:NO iconType:IconCloudTypeUpload]; [c addItemWithTitle:TITLE_SEED filter: TRINFOS_KEY_SEEDTORRENTS]; c.iconColor = [UIColor seedColor]; c.emptyTitle = NSLocalizedString(@"There are no seeding torrents to show", @"Category empty title"); [_items addObject:c]; - c = [StatusCategory categoryWithTitle:TITLE_STOP isAlwaysVisible:NO icon:[UIImage iconStop]]; + c = [StatusCategory categoryWithTitle:TITLE_STOP isAlwaysVisible:NO iconType:IconCloudTypeStop]; [c addItemWithTitle:TITLE_STOP filter: TRINFOS_KEY_STOPTORRENTS]; c.iconColor = [UIColor stopColor]; c.emptyTitle = NSLocalizedString(@"There are no stopped torrents to show", @"Category empty title"); [_items addObject:c]; - c = [StatusCategory categoryWithTitle:TITLE_CHECK isAlwaysVisible:NO icon:[UIImage iconCheck]]; + c = [StatusCategory categoryWithTitle:TITLE_CHECK isAlwaysVisible:NO iconType:IconCloudTypeCheck]; [c addItemWithTitle:TITLE_CHECK filter: TRINFOS_KEY_CHECKTORRENTS]; c.iconColor = [UIColor checkColor]; c.emptyTitle = NSLocalizedString(@"There are no checking torrents to show", @"Category empty title"); [_items addObject:c]; - c = [StatusCategory categoryWithTitle:TITLE_ERROR isAlwaysVisible:NO icon:[UIImage iconError]]; + c = [StatusCategory categoryWithTitle:TITLE_ERROR isAlwaysVisible:NO iconType:IconCloudTypeError]; [c addItemWithTitle:TITLE_ERROR filter: TRINFOS_KEY_ERRORTORRENTS]; c.iconColor = [UIColor errorColor]; c.emptyTitle = NSLocalizedString(@"There are no error torrents to show", @"Category empty title"); diff --git a/TransmissionRPCClient/StatusCategory.h b/TransmissionRPCClient/StatusCategory.h index fabe3fa..9446df3 100644 --- a/TransmissionRPCClient/StatusCategory.h +++ b/TransmissionRPCClient/StatusCategory.h @@ -8,6 +8,7 @@ #import #import "TRInfos.h" +#import "IconCloud.h" /*! StatusCategoryItem holds an array of TRInfo objects and @@ -59,7 +60,7 @@ @interface StatusCategory : NSObject /// convinience init method -+ (instancetype)categoryWithTitle:(NSString*)title isAlwaysVisible:(BOOL)visible icon:(UIImage*)icon; ++ (instancetype)categoryWithTitle:(NSString*)title isAlwaysVisible:(BOOL)visible iconType:(IconCloudType)iconType; /// add item to the items - (void)addItemWithTitle:(NSString*)title filter:(NSString*)filterString; @@ -84,11 +85,11 @@ */ - (StatusCategoryItem*)categoryItemWithTitle:(NSString*)categoryTitle; -@property(nonatomic) NSString *title; // title of category ("All", "Downloading", "Seeding", "Stopped" ... -@property(nonatomic) NSString *emptyTitle; // title of category when there are no items in it -@property(nonatomic) BOOL alwaysVisible; // visibility of this category (always visible or not) -@property(nonatomic,readonly) int count; // count of items it category (including all subcategories) -@property(nonatomic) UIImage *iconImage; // image of the category +@property(nonatomic) NSString *title; // title of category ("All", "Downloading", "Seeding", "Stopped" ... +@property(nonatomic) NSString *emptyTitle; // title of category when there are no items in it +@property(nonatomic) BOOL alwaysVisible; // visibility of this category (always visible or not) +@property(nonatomic,readonly) int count; // count of items it category (including all subcategories) +@property(nonatomic) IconCloudType iconType; // image of the category @property(nonatomic,readonly) NSArray *items; // array of StatusCategoryItem diff --git a/TransmissionRPCClient/StatusCategory.m b/TransmissionRPCClient/StatusCategory.m index 6f97ad9..ace4c38 100644 --- a/TransmissionRPCClient/StatusCategory.m +++ b/TransmissionRPCClient/StatusCategory.m @@ -65,12 +65,12 @@ NSMutableArray *_items; } -+ (instancetype)categoryWithTitle:(NSString *)title isAlwaysVisible:(BOOL)visible icon:(UIImage *)icon ++ (instancetype)categoryWithTitle:(NSString *)title isAlwaysVisible:(BOOL)visible iconType:(IconCloudType)iconType { - return [[StatusCategory alloc] initWithTitle:title isAlwaysVisible:visible icon:icon]; + return [[StatusCategory alloc] initWithTitle:title isAlwaysVisible:visible iconType:iconType]; } -- (instancetype)initWithTitle:(NSString*)title isAlwaysVisible:(BOOL)alwaysVisible icon:(UIImage*)icon +- (instancetype)initWithTitle:(NSString*)title isAlwaysVisible:(BOOL)alwaysVisible iconType:(IconCloudType)iconType { self = [super init]; @@ -79,7 +79,7 @@ _title = title; _alwaysVisible = alwaysVisible; _items = [NSMutableArray array]; - _iconImage = icon; + _iconType = iconType; } return self; diff --git a/TransmissionRPCClient/StatusListCell.h b/TransmissionRPCClient/StatusListCell.h index fedb412..95e9a6d 100644 --- a/TransmissionRPCClient/StatusListCell.h +++ b/TransmissionRPCClient/StatusListCell.h @@ -7,6 +7,7 @@ // #import +#import "IconCloud.h" #define CELL_ID_STATUSLIST @"statusListCell" @@ -14,6 +15,6 @@ @property (weak, nonatomic) IBOutlet UILabel *statusLabel; @property (weak, nonatomic) IBOutlet UILabel *numberLabel; -@property (weak, nonatomic) IBOutlet UIImageView *iconImg; +@property (weak, nonatomic) IBOutlet IconCloud *icon; @end diff --git a/TransmissionRPCClient/StatusListController.m b/TransmissionRPCClient/StatusListController.m index b474351..c0417c9 100644 --- a/TransmissionRPCClient/StatusListController.m +++ b/TransmissionRPCClient/StatusListController.m @@ -453,6 +453,17 @@ StatusCategory *c = [_items categoryAtIndex:i]; StatusListCell *cell = (StatusListCell*)c.cell; cell.numberLabel.text = [NSString stringWithFormat:@"%i", c.count]; + + IconCloudType iconType = c.iconType; + + if( iconType == IconCloudTypeActive ) + c.count > 0 ? [cell.icon playActivityAnimation] : [cell.icon stopActivityAnimation]; + else if( iconType == IconCloudTypeCheck ) + c.count > 0 ? [cell.icon playCheckAnimation] : [cell.icon stopCheckAnimation]; + else if( iconType == IconCloudTypeDownload ) + torrents.totalDownloadRate > 0 ? [cell.icon playDownloadAnimation] : [cell.icon stopDownloadAnimation ]; + else if( iconType == IconCloudTypeUpload ) + torrents.totalUploadRate > 0 ? [cell.icon playUploadAnimation] : [cell.icon stopUploadAnimation]; } _torrentController.items = _selectedCategory; @@ -1189,8 +1200,9 @@ // Configure the cell cell.numberLabel.text = @" "; cell.statusLabel.text = c.title; - cell.iconImg.image = c.iconImage; - cell.iconImg.tintColor = c.iconColor ? c.iconColor : cell.tintColor; + + cell.icon.iconType = c.iconType; + cell.icon.tintColor = c.iconColor ? c.iconColor : cell.tintColor; // store cell reference for later cell // updating diff --git a/TransmissionRPCClient/TRInfos.m b/TransmissionRPCClient/TRInfos.m index 93a467f..8bac2e0 100644 --- a/TransmissionRPCClient/TRInfos.m +++ b/TransmissionRPCClient/TRInfos.m @@ -19,6 +19,8 @@ { NSMutableDictionary *_chache; + long long _totalUploadRate; + long long _totalDownloadRate; } + (TRInfos *)infosFromArrayOfJSON:(NSArray *)jsonArray @@ -178,6 +180,11 @@ return str; } +- (long long)totalUploadRate +{ + return self.totalUploadRateString ? _totalUploadRate : 0; +} + #define CHACHE_KEY_TOTALDOWNSTR @"totalDownRateStr" - (NSString *)totalDownloadRateString { @@ -196,6 +203,11 @@ return str; } +- (long long)totalDownloadRate +{ + return self.totalDownloadRateString ? _totalDownloadRate : 0; +} + #define CHACHE_KEY_TOTALDOWNSIZESTR @"totalDownSize" - (NSString *)totalDownloadSizeString {