Skip to content

Commit 90e0595

Browse files
KM-13397 Remove Lottie dependency (#216)
* KM-13370 Improve reliability of loading animation presentation * KM-13397 Remove Lottie dependency
1 parent e492064 commit 90e0595

11 files changed

Lines changed: 117 additions & 270 deletions

File tree

LocalPackages/PIALibrary/Package.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ let package = Package(
2828
.package(url: "git@github.com:pia-foss/mobile-ios-openvpn.git", branch: "master"),
2929
.package(url: "git@github.com:pia-foss/mobile-ios-wireguard.git", revision: "bf7b4258d9c9279c6051bba0b7a73ca7d5f9547e"),
3030
.package(url: "https://github.com/hkellaway/Gloss.git", from: "3.1.0"),
31-
.package(url: "https://github.com/airbnb/lottie-ios.git", from: "3.4.1"),
3231
.package(url: "https://github.com/huri000/SwiftEntryKit.git", from: "1.0.3"),
3332
.package(url: "https://github.com/Orderella/PopupDialog.git", branch: "master"),
3433
.package(url: "https://github.com/SwiftyBeaver/SwiftyBeaver.git", from: "1.9.0"),
@@ -44,7 +43,6 @@ let package = Package(
4443
"PIALibraryUtilObjC",
4544
.product(name: "PopupDialog", package: "PopupDialog", condition: .when(platforms: [.iOS])),
4645
.product(name: "SwiftEntryKit", package: "SwiftEntryKit", condition: .when(platforms: [.iOS])),
47-
.product(name: "Lottie", package: "lottie-ios"),
4846
.product(name: "Reachability", package: "Reachability.swift"),
4947
.product(name: "PIAKPI", package: "mobile-ios-releases-kpi"),
5048
.product(name: "PIACSI", package: "mobile-ios-releases-csi"),

PIA VPN-tvOS/Resources/Licences.plist

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,6 @@
108108
<key>LicenseURL</key>
109109
<string>https://raw.githubusercontent.com/huri000/SwiftEntryKit/master/LICENSE</string>
110110
</dict>
111-
<dict>
112-
<key>Name</key>
113-
<string>lottie-ios</string>
114-
<key>Copyright</key>
115-
<string>Copyright 2018 Airbnb, Inc.</string>
116-
<key>LicenseURL</key>
117-
<string>https://raw.githubusercontent.com/airbnb/lottie-ios/master/LICENSE</string>
118-
</dict>
119111
<dict>
120112
<key>Name</key>
121113
<string>nanopb</string>

PIA VPN.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 0 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

PIA VPN/Resources/Components.plist

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,6 @@
135135
<key>LicenseURL</key>
136136
<string>https://raw.githubusercontent.com/huri000/SwiftEntryKit/master/LICENSE</string>
137137
</dict>
138-
<dict>
139-
<key>Name</key>
140-
<string>lottie-ios</string>
141-
<key>Copyright</key>
142-
<string>Copyright 2018 Airbnb, Inc.</string>
143-
<key>LicenseURL</key>
144-
<string>https://raw.githubusercontent.com/airbnb/lottie-ios/master/LICENSE</string>
145-
</dict>
146138
<dict>
147139
<key>Name</key>
148140
<string>nanopb</string>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"images" : [
3+
{
4+
"filename" : "pia-spinner.png",
5+
"idiom" : "universal"
6+
}
7+
],
8+
"info" : {
9+
"author" : "xcode",
10+
"version" : 1
11+
}
12+
}
52.8 KB
Loading

PIA VPN/Resources/Lottie/pia-spinner.json

Lines changed: 0 additions & 1 deletion
This file was deleted.

PIA VPN/UI/AutolayoutViewController.swift

Lines changed: 44 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
//
2222

2323
import UIKit
24-
import Lottie
2524
import PIALibrary
2625
/// Declares a generic, dismissable modal controller.
2726
public protocol ModalController: AnyObject {
@@ -72,9 +71,13 @@ open class AutolayoutViewController: UIViewController, ModalController, Restylab
7271
open var status: ViewControllerStatus = .initial {
7372
didSet { reloadFormElements() }
7473
}
75-
74+
75+
/// Loading view controller for showing animations
76+
private var loadingViewController: LoadingViewController?
77+
7678
deinit {
7779
NotificationCenter.default.removeObserver(self)
80+
loadingViewController?.view.removeFromSuperview()
7881
}
7982

8083
/// :nodoc:
@@ -221,139 +224,55 @@ open class AutolayoutViewController: UIViewController, ModalController, Restylab
221224
}
222225

223226
extension AutolayoutViewController: AnimatingLoadingDelegate {
224-
225-
private struct LottieRepos {
226-
static var graphLoad: AnimationView?
227-
static var containerView: UIView?
228-
}
229-
230-
var graphLoad: AnimationView? {
231-
get {
232-
return objc_getAssociatedObject(self, &LottieRepos.graphLoad) as? AnimationView
233-
}
234-
set {
235-
if let unwrappedValue = newValue {
236-
objc_setAssociatedObject(self, &LottieRepos.graphLoad, unwrappedValue as AnimationView?, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
237-
}
238-
}
239-
}
240-
241-
var containerView: UIView? {
242-
get {
243-
return LottieRepos.containerView
244-
}
245-
set {
246-
if let unwrappedValue = newValue {
247-
LottieRepos.containerView = unwrappedValue
248-
}
249-
}
250-
}
251227

252228
@objc public func showLoadingAnimation() {
253-
if graphLoad == nil {
254-
containerView = UIView(frame: UIScreen.main.bounds)
255-
containerView?.backgroundColor = Theme.current.palette.appearance == .dark ?
256-
UIColor.black.withAlphaComponent(0.72) :
257-
UIColor.piaGrey1.withAlphaComponent(0.75)
258-
graphLoad = AnimationView(name: "pia-spinner")
259-
}
260-
addLoadingAnimation()
261-
}
262-
263-
private func addLoadingAnimation() {
264-
graphLoad?.loopMode = .loop
265-
if let graphLoad = graphLoad,
266-
let containerView = containerView {
267-
if let key = self.navigationController?.view {
268-
key.addSubview(containerView)
269-
key.addSubview(graphLoad)
270-
}
271-
setLoadingConstraints()
272-
graphLoad.play()
229+
// If already showing, keep it
230+
guard loadingViewController == nil else { return }
231+
232+
guard
233+
let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
234+
let window = windowScene.windows.first
235+
else {
236+
return
273237
}
274-
}
275-
276-
@objc public func hideLoadingAnimation() {
277-
graphLoad?.stop()
278-
graphLoad?.removeFromSuperview()
279-
containerView?.removeFromSuperview()
280-
}
281-
282-
private func setLoadingConstraints() {
283-
if let graphLoad = graphLoad,
284-
let keyView = self.navigationController?.view,
285-
let containerView = containerView {
286-
287-
containerView.translatesAutoresizingMaskIntoConstraints = false
288-
graphLoad.translatesAutoresizingMaskIntoConstraints = false
289238

290-
NSLayoutConstraint(item: containerView,
291-
attribute: .left,
292-
relatedBy: .equal,
293-
toItem: keyView,
294-
attribute: .left,
295-
multiplier: 1.0,
296-
constant: 0.0).isActive = true
239+
// Lock UI
240+
window.isUserInteractionEnabled = false
297241

298-
NSLayoutConstraint(item: containerView,
299-
attribute: .right,
300-
relatedBy: .equal,
301-
toItem: keyView,
302-
attribute: .right,
303-
multiplier: 1.0,
304-
constant: 0.0).isActive = true
242+
let loadingVC = LoadingViewController()
243+
loadingVC.view.translatesAutoresizingMaskIntoConstraints = false
244+
self.loadingViewController = loadingVC
305245

306-
NSLayoutConstraint(item: containerView,
307-
attribute: .top,
308-
relatedBy: .equal,
309-
toItem: keyView,
310-
attribute: .top,
311-
multiplier: 1.0,
312-
constant: 0.0).isActive = true
246+
window.addSubview(loadingVC.view)
313247

314-
NSLayoutConstraint(item: containerView,
315-
attribute: .bottom,
316-
relatedBy: .equal,
317-
toItem: keyView,
318-
attribute: .bottom,
319-
multiplier: 1.0,
320-
constant: 0.0).isActive = true
248+
setupLoadingConstraints(
249+
loadingView: loadingVC.view,
250+
in: window
251+
)
252+
}
321253

322-
NSLayoutConstraint(item: graphLoad,
323-
attribute: .centerX,
324-
relatedBy: .equal,
325-
toItem: containerView,
326-
attribute: .centerX,
327-
multiplier: 1.0,
328-
constant: 0.0).isActive = true
329-
330-
NSLayoutConstraint(item: graphLoad,
331-
attribute: .centerY,
332-
relatedBy: .equal,
333-
toItem: containerView,
334-
attribute: .centerY,
335-
multiplier: 1.0,
336-
constant: 0.0).isActive = true
337-
338-
let lottieWidth = UIScreen.main.bounds.width/4
254+
@objc public func hideLoadingAnimation() {
255+
// Unlock UI
256+
let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
257+
let window = windowScene?.windows.first
258+
window?.isUserInteractionEnabled = true
339259

340-
NSLayoutConstraint(item: graphLoad,
341-
attribute: .width,
342-
relatedBy: .equal,
343-
toItem: nil,
344-
attribute: .width,
345-
multiplier: 1.0,
346-
constant: lottieWidth).isActive = true
347-
348-
NSLayoutConstraint(item: graphLoad,
349-
attribute: .height,
350-
relatedBy: .equal,
351-
toItem: nil,
352-
attribute: .height,
353-
multiplier: 1.0,
354-
constant: lottieWidth).isActive = true
260+
loadingViewController?.view.removeFromSuperview()
261+
loadingViewController = nil
262+
}
355263

356-
}
264+
private func setupLoadingConstraints(
265+
loadingView: UIView,
266+
in parentView: UIView
267+
) {
268+
// Loading view centered in parent with fixed size
269+
let loadingSize = UIScreen.main.bounds.width / 4
270+
NSLayoutConstraint.activate([
271+
loadingView.centerXAnchor.constraint(equalTo: parentView.centerXAnchor),
272+
loadingView.centerYAnchor.constraint(equalTo: parentView.centerYAnchor),
273+
loadingView.widthAnchor.constraint(equalToConstant: loadingSize),
274+
loadingView.heightAnchor.constraint(equalToConstant: loadingSize)
275+
])
357276
}
358277

359278
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//
2+
// LoadingView.swift
3+
// PIA VPN
4+
//
5+
// Created by Diego Trevisan on 16.12.25.
6+
// Copyright © 2025 Private Internet Access, Inc.
7+
//
8+
// This file is part of the Private Internet Access iOS Client.
9+
//
10+
// The Private Internet Access iOS Client is free software: you can redistribute it and/or
11+
// modify it under the terms of the GNU General Public License as published by the Free
12+
// Software Foundation, either version 3 of the License, or (at your option) any later version.
13+
//
14+
// The Private Internet Access iOS Client is distributed in the hope that it will be useful,
15+
// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16+
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17+
// details.
18+
//
19+
// You should have received a copy of the GNU General Public License along with the Private
20+
// Internet Access iOS Client. If not, see <https://www.gnu.org/licenses/>.
21+
//
22+
23+
import SwiftUI
24+
import UIKit
25+
26+
struct LoadingView: View {
27+
@State private var isRotating = false
28+
29+
var body: some View {
30+
Image(asset: Asset.Ui.piaSpinner)
31+
.resizable()
32+
.aspectRatio(contentMode: .fit)
33+
.rotationEffect(.degrees(isRotating ? 360 : 0))
34+
.animation(
35+
.linear(duration: 1.0)
36+
.repeatForever(autoreverses: false),
37+
value: isRotating
38+
)
39+
.onAppear {
40+
isRotating = true
41+
}
42+
}
43+
}
44+
45+
/// UIKit wrapper for LoadingView
46+
final class LoadingViewController: UIHostingController<LoadingView> {
47+
init() {
48+
super.init(rootView: LoadingView())
49+
view.backgroundColor = .clear
50+
}
51+
52+
@available(*, unavailable)
53+
required init?(coder aDecoder: NSCoder) {
54+
fatalError("init(coder:) has not been implemented")
55+
}
56+
}
57+
58+
#Preview {
59+
LoadingView()
60+
}

PIA VPN/UI/Shared/SwiftGen+Assets.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,7 @@ internal enum Asset {
464464
internal static let imageWalkthrough2 = ImageAsset(name: "image-walkthrough-2")
465465
internal static let imageWalkthrough3 = ImageAsset(name: "image-walkthrough-3")
466466
internal static let navLogo = ImageAsset(name: "nav-logo")
467+
internal static let piaSpinner = ImageAsset(name: "pia-spinner")
467468
internal static let qrCode = ImageAsset(name: "qr-code")
468469
}
469470
}

0 commit comments

Comments
 (0)