// // EKAttributes+Animation.swift // SwiftEntryKit // // Created by Daniel Huri on 4/21/18. // Copyright (c) 2018 huri000@gmail.com. All rights reserved. // import UIKit // A protocol that describes an animation protocol EKAnimation { var delay: TimeInterval { get set } var duration: TimeInterval { get set } var spring: EKAttributes.Animation.Spring? { get set } } // A protocol that describes a range animation protocol EKRangeAnimation: EKAnimation { var start: CGFloat { get set } var end: CGFloat { get set } } public extension EKAttributes { /** Describes an animation that can be performed on the entry */ struct Animation: Equatable { /** Describes properties for a spring animation that can be performed on the entry */ public struct Spring: Equatable { /** The dampic of the spring animation */ public var damping: CGFloat /** The initial velocity of the spring animation */ public var initialVelocity: CGFloat /** Initializer */ public init(damping: CGFloat, initialVelocity: CGFloat) { self.damping = damping self.initialVelocity = initialVelocity } } /** Describes an animation with range */ public struct RangeAnimation: EKRangeAnimation, Equatable { /** The duration of the range animation */ public var duration: TimeInterval /** The delay of the range animation */ public var delay: TimeInterval /** The start value of the range animation (e.g. alpha, scale) */ public var start: CGFloat /** The end value of the range animation (e.g. alpha, scale) */ public var end: CGFloat /** The spring of the animation */ public var spring: Spring? /** Initializer */ public init(from start: CGFloat, to end: CGFloat, duration: TimeInterval, delay: TimeInterval = 0, spring: Spring? = nil) { self.start = start self.end = end self.delay = delay self.duration = duration self.spring = spring } } /** Describes translation animation */ public struct Translate: EKAnimation, Equatable { /** Describes the anchor position */ public enum AnchorPosition: Equatable { /** Top position - the entry shows from top or exits towards the top */ case top /** Bottom position - the entry shows from bottom or exits towards the bottom */ case bottom /** Automatic position - the entry shows and exits according to EKAttributes.Position value. If the position of the entry is top, bottom, the entry's translation anchor is top, bottom - respectively.*/ case automatic } /** Animation duration */ public var duration: TimeInterval /** Animation delay */ public var delay: TimeInterval /** To where OR from the entry is animated */ public var anchorPosition: AnchorPosition /** Optional translation spring */ public var spring: Spring? /** Initializer */ public init(duration: TimeInterval, anchorPosition: AnchorPosition = .automatic, delay: TimeInterval = 0, spring: Spring? = nil) { self.anchorPosition = anchorPosition self.duration = duration self.delay = delay self.spring = spring } } /** Translation animation prop */ public var translate: Translate? /** Scale animation prop */ public var scale: RangeAnimation? /** Fade animation prop */ public var fade: RangeAnimation? /** Does the animation contains translation */ public var containsTranslation: Bool { return translate != nil } /** Does the animation contains scale */ public var containsScale: Bool { return scale != nil } /** Does the animation contains fade */ public var containsFade: Bool { return fade != nil } /** Does the animation contains any animation whatsoever */ public var containsAnimation: Bool { return containsTranslation || containsScale || containsFade } /** Returns the maximum delay amongst all animations */ public var maxDelay: TimeInterval { return max(translate?.delay ?? 0, max(scale?.delay ?? 0, fade?.delay ?? 0)) } /** Returns the maximum duration amongst all animations */ public var maxDuration: TimeInterval { return max(translate?.duration ?? 0, max(scale?.duration ?? 0, fade?.duration ?? 0)) } /** Returns the maximum (duration+delay) amongst all animations */ public var totalDuration: TimeInterval { return maxDelay + maxDuration } /** Returns the maximum (duration+delay) amongst all animations */ public static var translation: Animation { return Animation(translate: .init(duration: 0.3)) } /** No animation at all */ public static var none: Animation { return Animation() } /** Initializer */ public init(translate: Translate? = nil, scale: RangeAnimation? = nil, fade: RangeAnimation? = nil) { self.translate = translate self.scale = scale self.fade = fade } } }