Files
bundesmessenger-ios/Riot/Modules/Common/Flow/Animation.swift
T
Neil Alexander 86cb17876c Load animation, colour corrections, fixed launch screen
Squashed commit of the following:

commit e11d0e589469db9ead0d96449f9e31677edb2031
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Fri Jul 10 17:59:30 2020 +0100

    Fix colour in launch screen

commit aa59e85d309433a05992e446bdd789b59b87089d
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Fri Jul 10 17:57:01 2020 +0100

    Display -> display

commit 6da06421bedfe7aff6a0ff1dff4360685e708cf2
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Fri Jul 10 17:55:20 2020 +0100

    P3 colours

commit b1fc009ab9002eb75403c287ce75bdbf08e222cd
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Fri Jul 10 17:52:22 2020 +0100

    Update Riot.xcodeproj

commit ac1d994c6eb3f863f5310364ee4582476d59b76e
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Fri Jul 10 17:44:41 2020 +0100

    Revert changes to Images.swift and Storyboards.swift

commit 27c88f9b3ba7c22efd19f6e8aa17c2af17f3289b
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Fri Jul 10 17:25:08 2020 +0100

    Add animation source files

commit d19ccd50009280b45f3165e1a2a03a2bd241ccf7
Merge: d6b651a8 2ed92204
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Fri Jul 10 17:18:04 2020 +0100

    Fix launch screen and update loading screen

    Merge commit '2ed92204' into rebranding

commit 2ed922045cd6381202b8d7bb80136f8b24a95141
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Fri Jul 10 17:13:56 2020 +0100

    Fix launch screen, smooth transition to loading animation
2020-07-10 17:59:57 +01:00

152 lines
5.1 KiB
Swift

// Copyright © 2016-2019 JABT Labs Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: The above copyright
// notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
import UIKit
open class Animation: NSObject, CAAnimationDelegate {
/// Key frame animations which animate the properties of `layer`.
fileprivate var keyframeAnimations: [CAKeyframeAnimation]
/// The CALayer whose properties are animated.
open var layer: CALayer
/// Specifies whether or not the animation should autoreverse.
var autoreverses: Bool
/// Determines the number of times the animation will repeat.
///
/// May be fractional. If the repeatCount is 0, it is ignored.
/// Setting this property to greatestFiniteMagnitude will cause the animation to repeat forever.
var repeatCount: Float
weak var delegate: AnimationDelegate?
/// The current time of the animation. i.e. what time is being displayed.
var time: TimeInterval {
return layer.timeOffset
}
/// True if the animation is playing.
var playing: Bool {
return layer.speed != 0.0
}
// MARK: - Initializers
public init(layer: CALayer, keyframeAnimations: [CAKeyframeAnimation], autoreverses: Bool = false, repeatCount: Float = 0) {
self.layer = layer
self.keyframeAnimations = keyframeAnimations
self.autoreverses = autoreverses
self.repeatCount = repeatCount
super.init()
keyframeAnimations.forEach(configure)
reset()
}
private func configure(keyframeAnimation: CAKeyframeAnimation) {
keyframeAnimation.delegate = self
keyframeAnimation.isRemovedOnCompletion = false
keyframeAnimation.fillMode = .both
keyframeAnimation.autoreverses = autoreverses
keyframeAnimation.repeatCount = repeatCount
}
// MARK: - Playing & Resetting Animation
/// Resumes the animation from where it was paused.
open func play() {
let pausedTime = layer.timeOffset
layer.speed = 1.0
layer.timeOffset = 0.0
layer.beginTime = 0.0
let timeSincePause = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime
layer.beginTime = timeSincePause
}
/// Pauses the animation.
open func pause() {
let pausedTime = layer.convertTime(CACurrentMediaTime(), from: nil)
offset(to: pausedTime)
}
/// Resets the animation to time 0.
open func reset() {
CATransaction.suppressAnimations {
layer.removeAllAnimations()
layer.beginTime = 0
offset(to: 0)
for keyframeAnimation in keyframeAnimations {
layer.setValue(keyframeAnimation.values?.first, forKeyPath: keyframeAnimation.keyPath!)
}
addAllAnimations()
layer.speed = 0
}
}
/// Adds all the animations to `layer` so they can be played.
private func addAllAnimations() {
DispatchQueue.main.async { [weak self] in
guard let keyframeAnimations = self?.keyframeAnimations, let layer = self?.layer else {
return
}
for keyframeAnimation in keyframeAnimations {
layer.add(keyframeAnimation, forKey: keyframeAnimation.keyPath)
}
}
}
// MARK: - Driving Animation
/// Shows the animation at time `time`.
open func offset(to time: TimeInterval) {
layer.speed = 0.0
layer.timeOffset = time
}
// MARK: - CAAnimationDelegate
public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
guard flag else {
return
}
let time = autoreverses ? 0 : (keyframeAnimations.first?.duration ?? 0)
offset(to: time)
if let keyframeAnimation = anim as? CAKeyframeAnimation,
keyframeAnimations.first?.keyPath == keyframeAnimation.keyPath {
delegate?.didStop(animation: self)
}
}
}
public extension Animation {
var reversed: Animation {
let reversedKeyFrameAnimations = keyframeAnimations.map { $0.reversed }
return Animation(layer: layer, keyframeAnimations: reversedKeyFrameAnimations)
}
}
protocol AnimationDelegate: class {
func didStop(animation: Animation)
}