summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2022-07-27 08:31:30 +0200
committerAndrej Mihajlov <and@mullvad.net>2022-07-28 11:21:51 +0200
commita8b89ee5e9fe985120fa21b6fd0f0e4f6f344fd8 (patch)
tree705abf792168f002f622ff812a4eca5df68fecc6
parent5bd9fd932d0515bf3987d1fa8a5c28ca04cfd130 (diff)
downloadmullvadvpn-a8b89ee5e9fe985120fa21b6fd0f0e4f6f344fd8.tar.xz
mullvadvpn-a8b89ee5e9fe985120fa21b6fd0f0e4f6f344fd8.zip
Add custom size for spinner, integrate with scene API and sync all animations
-rw-r--r--ios/MullvadVPN/SpinnerActivityIndicatorView.swift91
1 files changed, 58 insertions, 33 deletions
diff --git a/ios/MullvadVPN/SpinnerActivityIndicatorView.swift b/ios/MullvadVPN/SpinnerActivityIndicatorView.swift
index 243389a3ff..4c7332ae6f 100644
--- a/ios/MullvadVPN/SpinnerActivityIndicatorView.swift
+++ b/ios/MullvadVPN/SpinnerActivityIndicatorView.swift
@@ -8,21 +8,23 @@
import UIKit
-private let kRotationAnimationKey = "rotation"
-private let kAnimationDuration = 0.6
-
class SpinnerActivityIndicatorView: UIView {
+ private static let rotationAnimationKey = "rotation"
+ private static let animationDuration = 0.6
+
enum Style {
- case small, medium, large
+ case small, medium, large, custom
var intrinsicSize: CGSize {
switch self {
case .small:
- return .init(width: 16, height: 16)
+ return CGSize(width: 16, height: 16)
case .medium:
- return .init(width: 20, height: 20)
+ return CGSize(width: 20, height: 20)
case .large:
- return .init(width: 60, height: 60)
+ return CGSize(width: 60, height: 60)
+ case .custom:
+ return CGSize(width: UIView.noIntrinsicMetric, height: UIView.noIntrinsicMetric)
}
}
}
@@ -32,8 +34,7 @@ class SpinnerActivityIndicatorView: UIView {
private(set) var isAnimating = false
private(set) var style = Style.large
- private var startTime = CFTimeInterval(0)
- private var stopTime = CFTimeInterval(0)
+ private var sceneActivationObserver: Any?
override var intrinsicContentSize: CGSize {
return style.intrinsicSize
@@ -42,28 +43,30 @@ class SpinnerActivityIndicatorView: UIView {
init(style: Style) {
self.style = style
- super.init(frame: CGRect(origin: .zero, size: style.intrinsicSize))
+ let size = style == .custom ? .zero : style.intrinsicSize
+
+ super.init(frame: CGRect(origin: .zero, size: size))
addSubview(imageView)
isHidden = true
backgroundColor = UIColor.clear
-
- NotificationCenter.default.addObserver(
- self,
- selector: #selector(restartAnimationIfNeeded),
- name: UIApplication.willEnterForegroundNotification,
- object: nil
- )
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
+ deinit {
+ unregisterSceneActivationObserver()
+ }
+
override func didMoveToWindow() {
super.didMoveToWindow()
- if window != nil {
+ if window == nil {
+ unregisterSceneActivationObserver()
+ } else {
+ registerSceneActivationObserver()
restartAnimationIfNeeded()
}
}
@@ -71,7 +74,9 @@ class SpinnerActivityIndicatorView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
- imageView.frame = CGRect(origin: .zero, size: style.intrinsicSize)
+ let size = style == .custom ? frame.size : style.intrinsicSize
+
+ imageView.frame = CGRect(origin: .zero, size: size)
}
func startAnimating() {
@@ -91,37 +96,57 @@ class SpinnerActivityIndicatorView: UIView {
}
private func addAnimation() {
- let timeOffset = stopTime - startTime
+ layer.add(createAnimation(), forKey: Self.rotationAnimationKey)
+ }
- let anim = animation()
- anim.timeOffset = timeOffset
+ private func removeAnimation() {
+ layer.removeAnimation(forKey: Self.rotationAnimationKey)
+ }
- layer.add(anim, forKey: kRotationAnimationKey)
+ private func registerSceneActivationObserver() {
+ let name: NSNotification.Name
+ var object: Any?
- startTime = layer.convertTime(CACurrentMediaTime(), from: nil) - timeOffset
- }
+ if #available(iOS 13, *) {
+ name = UIScene.willEnterForegroundNotification
+ object = window?.windowScene
+ } else {
+ name = UIApplication.willEnterForegroundNotification
+ }
- private func removeAnimation() {
- layer.removeAnimation(forKey: kRotationAnimationKey)
+ unregisterSceneActivationObserver()
+
+ sceneActivationObserver = NotificationCenter.default.addObserver(
+ forName: name,
+ object: object,
+ queue: .main, using: { [weak self] _ in
+ self?.restartAnimationIfNeeded()
+ })
+ }
- stopTime = layer.convertTime(CACurrentMediaTime(), from: nil)
+ private func unregisterSceneActivationObserver() {
+ if let sceneActivationObserver = sceneActivationObserver {
+ NotificationCenter.default.removeObserver(sceneActivationObserver)
+ self.sceneActivationObserver = nil
+ }
}
- @objc private func restartAnimationIfNeeded() {
- let anim = layer.animation(forKey: kRotationAnimationKey)
+ private func restartAnimationIfNeeded() {
+ let animation = layer.animation(forKey: Self.rotationAnimationKey)
- if isAnimating && anim == nil {
+ if isAnimating && animation == nil {
removeAnimation()
addAnimation()
}
}
- private func animation() -> CABasicAnimation {
+ private func createAnimation() -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: "transform.rotation")
animation.toValue = NSNumber(value: Double.pi * 2)
- animation.duration = kAnimationDuration
+ animation.duration = Self.animationDuration
animation.repeatCount = Float.infinity
animation.timingFunction = CAMediaTimingFunction(name: .linear)
+ animation.timeOffset = layer.convertTime(CACurrentMediaTime(), from: nil)
return animation
}