<commit_before>//
//  Created by <NAME> on 09/04/16.
//  Copyright © 2016 IBAnimatable. All rights reserved.
//

import UIKit

public class FoldAnimator: NSObject, AnimatedTransitioning {
  // MARK: - AnimatorProtocol
  public var transitionAnimationType: TransitionAnimationType
  public var transitionDuration: Duration = defaultTransitionDuration
  public var reverseAnimationType: TransitionAnimationType?
  public var interactiveGestureType: InteractiveGestureType?
  
  // MARK: - Private params
  fileprivate var fromDirection: TransitionAnimationType.Direction
  fileprivate var folds: Int = 2
  
  // MARK: - Private fold transition
  fileprivate var transform: CATransform3D = CATransform3DIdentity
  fileprivate var reverse: Bool = false
  fileprivate var horizontal: Bool = false
  fileprivate var size: CGSize = CGSize.zero
  fileprivate var foldSize: CGFloat = 0.0
  fileprivate var width: CGFloat {
      return horizontal ? size.width : size.height
  }
  fileprivate var height: CGFloat {
    return horizontal ? size.height : size.width
  }
  
  // MARK: - Life cycle
  public init(from direction: TransitionAnimationType.Direction, folds: Int?, transitionDuration: Duration) {
    fromDirection = direction
    self.transitionDuration = transitionDuration
    horizontal = fromDirection.isHorizontal
    
    if let folds = folds {
      self.folds = folds
    }
    
    switch fromDirection {
    case .right:
      self.transitionAnimationType = .fold(from: .right, folds: folds)
      self.reverseAnimationType = .fold(from: .left, folds: folds)
      self.interactiveGestureType = .pan(from: .left)
      reverse = true
    case .top:
      self.transitionAnimationType = .fold(from: .top, folds: folds)
      self.reverseAnimationType = .fold(from: .bottom, folds: folds)
      self.interactiveGestureType = .pan(from: .bottom)
      reverse = false
    case .bottom:
      self.transitionAnimationType = .fold(from: .bottom, folds: folds)
      self.reverseAnimationType = .fold(from: .top, folds: folds)
      self.interactiveGestureType = .pan(from: .top)
      reverse = true
    default:
      self.transitionAnimationType = .fold(from: .left, folds: folds)
      self.reverseAnimationType = .fold(from: .right, folds: folds)
      self.interactiveGestureType = .pan(from: .right)
      reverse = false      
    }
    super.init()
  }
}

extension FoldAnimator: UIViewControllerAnimatedTransitioning {
  public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return retrieveTransitionDuration(transitionContext: transitionContext)
  }
  
  public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    let (tempfromView, tempToView, tempContainerView) = retrieveViews(transitionContext: transitionContext)
    guard let fromView = tempfromView, let toView = tempToView, let containerView = tempContainerView else {
      transitionContext.completeTransition(true)
      return
    }
    
    toView.frame = toView.frame.offsetBy(dx: toView.frame.size.width, dy: 0)
    containerView.addSubview(toView)
    
    transform.m34 = -0.005
    containerView.layer.sublayerTransform = transform
    
    size = toView.frame.size
    foldSize = width * 0.5 / CGFloat(folds)

    let viewFolds = createSnapshots(toView: toView, fromView: fromView, containerView: containerView)
    animateFoldTransition(fromView: fromView, toViewFolds: viewFolds[0], fromViewFolds: viewFolds[1], completion: {
      if !transitionContext.transitionWasCancelled {
        toView.frame = containerView.bounds
        fromView.frame = containerView.bounds
      } else {
        fromView.frame = containerView.bounds
      }
      
      transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
      }
    )
  }
  
}

// MARK: - Setup fold transition

private extension FoldAnimator {
  
  func createSnapshots(toView: UIView, fromView: UIView, containerView: UIView) -> [[UIView]] {
    var fromViewFolds = [UIView]()
    var toViewFolds = [UIView]()
    for i in 0..<folds {
      let offset = CGFloat(i) * foldSize * 2
      let leftFromViewFold = createSnapshot(fromView: fromView, afterUpdates: false, offset: offset, left: true)
      var axesValues = valuesForAxe(initialValue: offset, reverseValue: height / 2)
      leftFromViewFold.layer.position = CGPoint(x: axesValues.0, y: axesValues.1)
      fromViewFolds.append(leftFromViewFold)
      leftFromViewFold.subviews[1].alpha = 0.0

      let rightFromViewFold = createSnapshot(fromView: fromView, afterUpdates: false, offset: offset + foldSize, left: false)
      axesValues = valuesForAxe(initialValue: offset + foldSize * 2, reverseValue: height / 2)
      rightFromViewFold.layer.position = CGPoint(x: axesValues.0, y: axesValues.1)
      fromViewFolds.append(rightFromViewFold)
      rightFromViewFold.subviews[1].alpha = 0.0

      let leftToViewFold = createSnapshot(fromView: toView, afterUpdates: true, offset: offset, left: true)
      axesValues = valuesForAxe(initialValue: self.reverse ? width : 0.0, reverseValue: height / 2)
      leftToViewFold.layer.position = CGPoint(x: axesValues.0, y: axesValues.1)
      axesValues = valuesForAxe(initialValue: 0.0, reverseValue: 1.0)
      leftToViewFold.layer.transform = CATransform3DMakeRotation(.pi * 2, axesValues.0, axesValues.1, 0.0)
      toViewFolds.append(leftToViewFold)

      let rightToViewFold = createSnapshot(fromView: toView, afterUpdates: true, offset: offset + foldSize, left: false)
      axesValues = valuesForAxe(initialValue: self.reverse ? width : 0.0, reverseValue: height / 2)
      rightToViewFold.layer.position = CGPoint(x: axesValues.0, y: axesValues.1)
      axesValues = valuesForAxe(initialValue: 0.0, reverseValue: 1.0)
      rightToViewFold.layer.transform = CATransform3DMakeRotation(-.pi * 2, axesValues.0, axesValues.1, 0.0)
      toViewFolds.append(rightToViewFold)
    }
    return [toViewFolds, fromViewFolds]
  }
  
  func createSnapshot(fromView view: UIView, afterUpdates: Bool, offset: CGFloat, left: Bool) -> UIView {
    let containerView = view.superview
    var snapshotView: UIView
    var axesValues = valuesForAxe(initialValue: offset, reverseValue: 0.0)
    let axesValues2 = valuesForAxe(initialValue: foldSize, reverseValue: height)
    let snapshotRegion = CGRect(x: axesValues.0, y: axesValues.1, width: axesValues2.0, height: axesValues2.1)
    if !afterUpdates {
      snapshotView = view.resizableSnapshotView(from: snapshotRegion, afterScreenUpdates: afterUpdates, withCapInsets: .zero)!
    } else {
      axesValues = valuesForAxe(initialValue: foldSize, reverseValue: height)
      snapshotView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: axesValues.0, height: axesValues.1))
      snapshotView.backgroundColor = view.backgroundColor
      let subSnapshotView = view.resizableSnapshotView(from: snapshotRegion, afterScreenUpdates: afterUpdates, withCapInsets: .zero)
      snapshotView.addSubview(subSnapshotView!)
    }
    
    let snapshotWithShadowView = addShadow(toView: snapshotView, reverse: left)
    containerView?.addSubview(snapshotWithShadowView)
    axesValues = valuesForAxe(initialValue: left ? 0.0 : 1.0, reverseValue: 0.5)
    snapshotWithShadowView.layer.anchorPoint = CGPoint(x: axesValues.0, y: axesValues.1)
    return snapshotWithShadowView
  }
  
  func addShadow(toView view: UIView, reverse: Bool) -> UIView {
    let viewWithShadow = UIView(frame: view.frame)
    let shadowView = UIView(frame: viewWithShadow.bounds)
    let gradient = CAGradientLayer()
    gradient.frame = shadowView.bounds
    gradient.colors = [UIColor(white: 0.0, alpha: 0.0).cgColor, UIColor(white: 0.0, alpha: 1.0).cgColor]
    if horizontal {
      var axesValues = valuesForAxe(initialValue: reverse ? 0.0 : 1.0, reverseValue: reverse ? 0.2 : 0.0)
      gradient.startPoint = CGPoint(x: axesValues.0, y: axesValues.1)
      axesValues = valuesForAxe(initialValue: reverse ? 1.0 : 0.0, reverseValue: reverse ? 0.0 : 1.0)
      gradient.endPoint = CGPoint(x: axesValues.0, y: axesValues.1)
    } else {
      var axesValues = valuesForAxe(initialValue: reverse ? 0.2 : 0.0, reverseValue: reverse ? 0.0 : 1.0)
      gradient.startPoint = CGPoint(x: axesValues.0, y: axesValues.1)<commit_msg>Refactor `FoldAnimator`<commit_after>//
//  Created by <NAME> on 09/04/16.
//  Copyright © 2016 IBAnimatable. All rights reserved.
//

import UIKit

public class FoldAnimator: NSObject, AnimatedTransitioning {
  // MARK: - AnimatorProtocol
  public var transitionAnimationType: TransitionAnimationType
  public var transitionDuration: Duration = defaultTransitionDuration
  public var reverseAnimationType: TransitionAnimationType?
  public var interactiveGestureType: InteractiveGestureType?
  
  // MARK: - Private params
  fileprivate var fromDirection: TransitionAnimationType.Direction
  fileprivate var folds: Int = 2
  
  // MARK: - Private fold transition
  fileprivate var transform: CATransform3D = CATransform3DIdentity
  fileprivate var reverse: Bool = false
  fileprivate var horizontal: Bool = false
  fileprivate var size: CGSize = CGSize.zero
  fileprivate var foldSize: CGFloat = 0.0
  fileprivate var width: CGFloat {
      return horizontal ? size.width : size.height
  }
  fileprivate var height: CGFloat {
    return horizontal ? size.height : size.width
  }
  
  // MARK: - Life cycle
  public init(from direction: TransitionAnimationType.Direction, folds: Int?, transitionDuration: Duration) {
    fromDirection = direction
    self.transitionDuration = transitionDuration
    horizontal = fromDirection.isHorizontal
    
    if let folds = folds {
      self.folds = folds
    }
    
    switch fromDirection {
    case .right:
      self.transitionAnimationType = .fold(from: .right, folds: folds)
      self.reverseAnimationType = .fold(from: .left, folds: folds)
      self.interactiveGestureType = .pan(from: .left)
      reverse = true
    case .top:
      self.transitionAnimationType = .fold(from: .top, folds: folds)
      self.reverseAnimationType = .fold(from: .bottom, folds: folds)
      self.interactiveGestureType = .pan(from: .bottom)
      reverse = false
    case .bottom:
      self.transitionAnimationType = .fold(from: .bottom, folds: folds)
      self.reverseAnimationType = .fold(from: .top, folds: folds)
      self.interactiveGestureType = .pan(from: .top)
      reverse = true
    default:
      self.transitionAnimationType = .fold(from: .left, folds: folds)
      self.reverseAnimationType = .fold(from: .right, folds: folds)
      self.interactiveGestureType = .pan(from: .right)
      reverse = false      
    }
    super.init()
  }
}

extension FoldAnimator: UIViewControllerAnimatedTransitioning {
  public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return retrieveTransitionDuration(transitionContext: transitionContext)
  }
  
  public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    let (tempfromView, tempToView, tempContainerView) = retrieveViews(transitionContext: transitionContext)
    guard let fromView = tempfromView, let toView = tempToView, let containerView = tempContainerView else {
      transitionContext.completeTransition(true)
      return
    }
    
    toView.frame = toView.frame.offsetBy(dx: toView.frame.size.width, dy: 0)
    containerView.addSubview(toView)
    
    transform.m34 = -0.005
    containerView.layer.sublayerTransform = transform
    
    size = toView.frame.size
    foldSize = width * 0.5 / CGFloat(folds)

    let viewFolds = makeSnapshots(toView: toView, fromView: fromView, containerView: containerView)
    animateFoldTransition(fromView: fromView, toViewFolds: viewFolds[0], fromViewFolds: viewFolds[1], completion: {
      if !transitionContext.transitionWasCancelled {
        toView.frame = containerView.bounds
        fromView.frame = containerView.bounds
      } else {
        fromView.frame = containerView.bounds
      }
      
      transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
      }
    )
  }
  
}

// MARK: - Setup fold transition

private extension FoldAnimator {
  
  func makeSnapshots(toView: UIView, fromView: UIView, containerView: UIView) -> [[UIView]] {
    var fromViewFolds = [UIView]()
    var toViewFolds = [UIView]()
    for i in 0..<folds {
      let offset = CGFloat(i) * foldSize * 2
      let leftFromViewFold = makeSnapshot(from: fromView, afterUpdates: false, offset: offset, left: true)
      var axesValues = valuesForAxe(initialValue: offset, reverseValue: height / 2)
      leftFromViewFold.layer.position = CGPoint(x: axesValues.0, y: axesValues.1)
      fromViewFolds.append(leftFromViewFold)
      leftFromViewFold.subviews[1].alpha = 0.0

      let rightFromViewFold = makeSnapshot(from: fromView, afterUpdates: false, offset: offset + foldSize, left: false)
      axesValues = valuesForAxe(initialValue: offset + foldSize * 2, reverseValue: height / 2)
      rightFromViewFold.layer.position = CGPoint(x: axesValues.0, y: axesValues.1)
      fromViewFolds.append(rightFromViewFold)
      rightFromViewFold.subviews[1].alpha = 0.0

      let leftToViewFold = makeSnapshot(from: toView, afterUpdates: true, offset: offset, left: true)
      axesValues = valuesForAxe(initialValue: self.reverse ? width : 0.0, reverseValue: height / 2)
      leftToViewFold.layer.position = CGPoint(x: axesValues.0, y: axesValues.1)
      axesValues = valuesForAxe(initialValue: 0.0, reverseValue: 1.0)
      leftToViewFold.layer.transform = CATransform3DMakeRotation(.pi * 2, axesValues.0, axesValues.1, 0.0)
      toViewFolds.append(leftToViewFold)

      let rightToViewFold = makeSnapshot(from: toView, afterUpdates: true, offset: offset + foldSize, left: false)
      axesValues = valuesForAxe(initialValue: self.reverse ? width : 0.0, reverseValue: height / 2)
      rightToViewFold.layer.position = CGPoint(x: axesValues.0, y: axesValues.1)
      axesValues = valuesForAxe(initialValue: 0.0, reverseValue: 1.0)
      rightToViewFold.layer.transform = CATransform3DMakeRotation(-.pi * 2, axesValues.0, axesValues.1, 0.0)
      toViewFolds.append(rightToViewFold)
    }
    return [toViewFolds, fromViewFolds]
  }
  
  func makeSnapshot(from view: UIView, afterUpdates: Bool, offset: CGFloat, left: Bool) -> UIView {
    let containerView = view.superview
    var snapshotView: UIView
    var axesValues = valuesForAxe(initialValue: offset, reverseValue: 0.0)
    let axesValues2 = valuesForAxe(initialValue: foldSize, reverseValue: height)
    let snapshotRegion = CGRect(x: axesValues.0, y: axesValues.1, width: axesValues2.0, height: axesValues2.1)
    if !afterUpdates {
      snapshotView = view.resizableSnapshotView(from: snapshotRegion, afterScreenUpdates: afterUpdates, withCapInsets: .zero)!
    } else {
      axesValues = valuesForAxe(initialValue: foldSize, reverseValue: height)
      snapshotView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: axesValues.0, height: axesValues.1))
      snapshotView.backgroundColor = view.backgroundColor
      let subSnapshotView = view.resizableSnapshotView(from: snapshotRegion, afterScreenUpdates: afterUpdates, withCapInsets: .zero)
      snapshotView.addSubview(subSnapshotView!)
    }
    
    let snapshotWithShadowView = addShadow(to: snapshotView, reverse: left)
    containerView?.addSubview(snapshotWithShadowView)
    axesValues = valuesForAxe(initialValue: left ? 0.0 : 1.0, reverseValue: 0.5)
    snapshotWithShadowView.layer.anchorPoint = CGPoint(x: axesValues.0, y: axesValues.1)
    return snapshotWithShadowView
  }
  
  func addShadow(to view: UIView, reverse: Bool) -> UIView {
    let viewWithShadow = UIView(frame: view.frame)
    let shadowView = UIView(frame: viewWithShadow.bounds)
    let gradient = CAGradientLayer()
    gradient.frame = shadowView.bounds
    gradient.colors = [UIColor(white: 0.0, alpha: 0.0).cgColor, UIColor(white: 0.0, alpha: 1.0).cgColor]
    if horizontal {
      var axesValues = valuesForAxe(initialValue: reverse ? 0.0 : 1.0, reverseValue: reverse ? 0.2 : 0.0)
      gradient.startPoint = CGPoint(x: axesValues.0, y: axesValues.1)
      axesValues = valuesForAxe(initialValue: reverse ? 1.0 : 0.0, reverseValue: reverse ? 0.0 : 1.0)
      gradient.endPoint = CGPoint(x: axesValues.0, y: axesValues.1)
    } else {
      var axesValues = valuesForAxe(initialValue: reverse ? 0.2 : 0.0, reverseValue: reverse ? 0.0 : 1.0)
      gradient.startPoint = CGPoint(x: axesValues.0, y: axesValues.1)
{'fraction_non_alphanumeric': 0.0968014484007242, 'fraction_numerical': 0.015932407966203984, 'mean_word_length': 3.819953461314718, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5085062', 'n_tokens_mistral': 5319, 'n_tokens_neox': 4985, 'n_words': 1188}