capacitor-lottie-splash 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/android/src/main/java/com/headcount/plugins/lottiesplash/LottieSplashCoordinator.kt +29 -2
- package/dist/esm/web.d.ts +1 -0
- package/dist/esm/web.js +23 -7
- package/dist/plugin.cjs.js +23 -7
- package/dist/plugin.js +23 -7
- package/ios/Sources/LottieSplashPlugin/LottieSplashCoordinator.swift +15 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ The documented HeadCount defaults are light `#f0f0f0 → #f5f5f5` and dark `#1e1
|
|
|
101
101
|
|
|
102
102
|
## Recovery and accessibility
|
|
103
103
|
|
|
104
|
-
When playback completes before readiness, its final frame holds. After one second, a subtle indeterminate progress rail appears beneath the mark and remains visible until the application is ready. Reduced-motion and asset failures retain the theme-matched native cover instead of exposing a blank screen.
|
|
104
|
+
Each presentation fades in over 500 milliseconds before Lottie playback begins, then fades out over 500 milliseconds when the application is ready. When playback completes before readiness, its final frame holds. After one second, a subtle indeterminate progress rail appears beneath the mark and remains visible until the application is ready. Reduced-motion and asset failures retain the theme-matched native cover instead of exposing a blank screen.
|
|
105
105
|
|
|
106
106
|
For a staged native/over-the-air rollout, the consuming app must keep its web bundle and native host compatible. The native cover stays visible until the app-ready latch is set.
|
|
107
107
|
|
|
@@ -79,6 +79,7 @@ object LottieSplashCoordinator {
|
|
|
79
79
|
// incorrectly dismissing a healthy native cover during that startup work.
|
|
80
80
|
private const val WEB_ADOPTION_GRACE_MS = 30_000L
|
|
81
81
|
private const val PROGRESS_DELAY_MS = 1_000L
|
|
82
|
+
private const val COVER_FADE_IN_MS = 500L
|
|
82
83
|
private const val COVER_FADE_OUT_MS = 500L
|
|
83
84
|
private val main = Handler(Looper.getMainLooper())
|
|
84
85
|
|
|
@@ -88,6 +89,8 @@ object LottieSplashCoordinator {
|
|
|
88
89
|
private var hostForeground = false
|
|
89
90
|
private var systemHandoffComplete = true
|
|
90
91
|
private var compositionReady = false
|
|
92
|
+
private var coverFadeInStarted = false
|
|
93
|
+
private var coverFadeInComplete = false
|
|
91
94
|
private var requestedPlayback = AndroidSplashPlayback.PLAY
|
|
92
95
|
private var loadingRail: LottieSplashLoadingRail? = null
|
|
93
96
|
private var presentationId: String? = null
|
|
@@ -135,6 +138,8 @@ object LottieSplashCoordinator {
|
|
|
135
138
|
hostForeground = activity.hasWindowFocus()
|
|
136
139
|
systemHandoffComplete = !dismissWhenUnadopted
|
|
137
140
|
compositionReady = false
|
|
141
|
+
coverFadeInStarted = false
|
|
142
|
+
coverFadeInComplete = false
|
|
138
143
|
requestedPlayback = playback
|
|
139
144
|
presentationId = UUID.randomUUID().toString()
|
|
140
145
|
phase = AndroidSplashPhase.PREPARING
|
|
@@ -154,7 +159,7 @@ object LottieSplashCoordinator {
|
|
|
154
159
|
isClickable = true
|
|
155
160
|
isFocusable = true
|
|
156
161
|
contentDescription = "Loading application"
|
|
157
|
-
alpha =
|
|
162
|
+
alpha = 0f
|
|
158
163
|
background = GradientDrawable(
|
|
159
164
|
GradientDrawable.Orientation.LEFT_RIGHT,
|
|
160
165
|
if (darkTheme) intArrayOf(backgroundStart, Color.rgb(37, 37, 37))
|
|
@@ -171,6 +176,7 @@ object LottieSplashCoordinator {
|
|
|
171
176
|
overlay.post { updateAnimationLayout(overlay, lottie) }
|
|
172
177
|
cover = overlay
|
|
173
178
|
animation = lottie
|
|
179
|
+
if (systemHandoffComplete) beginCoverFadeIn(presentationId!!, overlay, lottie)
|
|
174
180
|
if (dismissWhenUnadopted) scheduleUnadoptedFallback(presentationId!!)
|
|
175
181
|
emit()
|
|
176
182
|
|
|
@@ -217,6 +223,7 @@ object LottieSplashCoordinator {
|
|
|
217
223
|
val id = presentationId ?: return
|
|
218
224
|
val existingCover = cover ?: return
|
|
219
225
|
val existingAnimation = animation ?: return
|
|
226
|
+
beginCoverFadeIn(id, existingCover, existingAnimation)
|
|
220
227
|
startPlaybackWhenVisible(id, existingCover, existingAnimation)
|
|
221
228
|
}
|
|
222
229
|
|
|
@@ -283,7 +290,7 @@ object LottieSplashCoordinator {
|
|
|
283
290
|
}
|
|
284
291
|
|
|
285
292
|
private fun startPlaybackWhenVisible(id: String, overlay: FrameLayout, lottie: LottieAnimationView) {
|
|
286
|
-
if (id != presentationId || cover !== overlay || animation !== lottie || !compositionReady || !hostForeground || !systemHandoffComplete || phase != AndroidSplashPhase.PREPARING) return
|
|
293
|
+
if (id != presentationId || cover !== overlay || animation !== lottie || !compositionReady || !coverFadeInComplete || !hostForeground || !systemHandoffComplete || phase != AndroidSplashPhase.PREPARING) return
|
|
287
294
|
val composition = lottie.composition ?: return
|
|
288
295
|
phase = AndroidSplashPhase.PLAYING
|
|
289
296
|
emit()
|
|
@@ -312,6 +319,22 @@ object LottieSplashCoordinator {
|
|
|
312
319
|
}
|
|
313
320
|
}
|
|
314
321
|
|
|
322
|
+
private fun beginCoverFadeIn(id: String, overlay: FrameLayout, lottie: LottieAnimationView) {
|
|
323
|
+
if (id != presentationId || cover !== overlay || animation !== lottie || coverFadeInStarted || !systemHandoffComplete) return
|
|
324
|
+
coverFadeInStarted = true
|
|
325
|
+
overlay.animate()
|
|
326
|
+
.alpha(1f)
|
|
327
|
+
.setDuration(if (ValueAnimator.areAnimatorsEnabled()) COVER_FADE_IN_MS else 0)
|
|
328
|
+
.setInterpolator(AccelerateDecelerateInterpolator())
|
|
329
|
+
.withEndAction {
|
|
330
|
+
if (id == presentationId && cover === overlay && animation === lottie) {
|
|
331
|
+
coverFadeInComplete = true
|
|
332
|
+
startPlaybackWhenVisible(id, overlay, lottie)
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
.start()
|
|
336
|
+
}
|
|
337
|
+
|
|
315
338
|
private fun updateAnimationLayout(overlay: FrameLayout, lottie: LottieAnimationView) {
|
|
316
339
|
if (cover !== overlay || animation !== lottie || overlay.width <= 0 || overlay.height <= 0) return
|
|
317
340
|
val availableWidth = minOf(overlay.width.toFloat(), overlay.height * 0.75f)
|
|
@@ -424,6 +447,8 @@ object LottieSplashCoordinator {
|
|
|
424
447
|
presentationId = null
|
|
425
448
|
phase = AndroidSplashPhase.HIDDEN
|
|
426
449
|
compositionReady = false
|
|
450
|
+
coverFadeInStarted = false
|
|
451
|
+
coverFadeInComplete = false
|
|
427
452
|
emit()
|
|
428
453
|
callback(null)
|
|
429
454
|
}.start()
|
|
@@ -444,6 +469,8 @@ object LottieSplashCoordinator {
|
|
|
444
469
|
presentationId = null
|
|
445
470
|
phase = AndroidSplashPhase.HIDDEN
|
|
446
471
|
compositionReady = false
|
|
472
|
+
coverFadeInStarted = false
|
|
473
|
+
coverFadeInComplete = false
|
|
447
474
|
pendingHide = null
|
|
448
475
|
completion = null
|
|
449
476
|
emit()
|
package/dist/esm/web.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export declare class LottieSplashWeb extends WebPlugin implements LottieSplashPl
|
|
|
6
6
|
private resolvePlayback?;
|
|
7
7
|
private overlay?;
|
|
8
8
|
private progressTimer?;
|
|
9
|
+
private playbackTimer?;
|
|
9
10
|
show(options: SplashShowOptions): Promise<Presentation>;
|
|
10
11
|
setLaunchTheme(_options: SplashLaunchThemeOptions): Promise<void>;
|
|
11
12
|
waitForCompletion(options: {
|
package/dist/esm/web.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { WebPlugin } from '@capacitor/core';
|
|
2
2
|
import { SplashStateMachine } from './state-machine';
|
|
3
3
|
const PROGRESS_DELAY_MS = 1_000;
|
|
4
|
+
const COVER_FADE_MS = 500;
|
|
4
5
|
export class LottieSplashWeb extends WebPlugin {
|
|
5
6
|
stateMachine = new SplashStateMachine();
|
|
6
7
|
playbackPromise;
|
|
7
8
|
resolvePlayback;
|
|
8
9
|
overlay;
|
|
9
10
|
progressTimer;
|
|
11
|
+
playbackTimer;
|
|
10
12
|
async show(options) {
|
|
11
13
|
const state = this.stateMachine.current();
|
|
12
14
|
if (state.visible && state.presentationId)
|
|
@@ -30,7 +32,7 @@ export class LottieSplashWeb extends WebPlugin {
|
|
|
30
32
|
this.emitState();
|
|
31
33
|
if (!state.playbackSettled)
|
|
32
34
|
await this.waitForCompletion(options);
|
|
33
|
-
this.removeOverlay(options.presentationId);
|
|
35
|
+
await this.removeOverlay(options.presentationId);
|
|
34
36
|
}
|
|
35
37
|
async getState() {
|
|
36
38
|
const { generation: _generation, ...state } = this.stateMachine.current();
|
|
@@ -47,10 +49,14 @@ export class LottieSplashWeb extends WebPlugin {
|
|
|
47
49
|
overlay.dataset.presentationId = presentationId;
|
|
48
50
|
Object.assign(overlay.style, {
|
|
49
51
|
position: 'fixed', inset: '0', zIndex: '2147483647', display: 'grid', placeItems: 'center',
|
|
50
|
-
background: this.backgroundFor(this.stateMachine.current().theme), overflow: 'hidden'
|
|
52
|
+
background: this.backgroundFor(this.stateMachine.current().theme), overflow: 'hidden',
|
|
53
|
+
opacity: '0', transition: `opacity ${COVER_FADE_MS}ms ease-in-out`
|
|
51
54
|
});
|
|
52
55
|
document.body.append(overlay);
|
|
53
56
|
this.overlay = overlay;
|
|
57
|
+
// Force the initial transparent style to paint before beginning the fade.
|
|
58
|
+
void overlay.offsetWidth;
|
|
59
|
+
overlay.style.opacity = '1';
|
|
54
60
|
// A generic package cannot ship HeadCount assets. The host supplies an approved local
|
|
55
61
|
// composition; absent or failed assets leave the opaque branded background in place.
|
|
56
62
|
if (!options.assets?.animationData && !options.assets?.animationPath) {
|
|
@@ -61,9 +67,13 @@ export class LottieSplashWeb extends WebPlugin {
|
|
|
61
67
|
this.settle(presentationId, 'reduced-motion', 'Reduced motion is enabled');
|
|
62
68
|
return;
|
|
63
69
|
}
|
|
64
|
-
this.
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
this.playbackTimer = window.setTimeout(() => {
|
|
71
|
+
if (this.stateMachine.current().presentationId !== presentationId || this.overlay !== overlay)
|
|
72
|
+
return;
|
|
73
|
+
this.stateMachine.playing(presentationId);
|
|
74
|
+
this.emitState();
|
|
75
|
+
void this.playComposition(options, presentationId);
|
|
76
|
+
}, COVER_FADE_MS);
|
|
67
77
|
}
|
|
68
78
|
async playComposition(options, presentationId) {
|
|
69
79
|
try {
|
|
@@ -124,9 +134,15 @@ export class LottieSplashWeb extends WebPlugin {
|
|
|
124
134
|
rail.append(segment);
|
|
125
135
|
this.overlay?.append(style, rail);
|
|
126
136
|
}
|
|
127
|
-
removeOverlay(presentationId) {
|
|
137
|
+
async removeOverlay(presentationId) {
|
|
128
138
|
window.clearTimeout(this.progressTimer);
|
|
129
|
-
this.
|
|
139
|
+
window.clearTimeout(this.playbackTimer);
|
|
140
|
+
const overlay = this.overlay;
|
|
141
|
+
if (overlay) {
|
|
142
|
+
overlay.style.opacity = '0';
|
|
143
|
+
await new Promise(resolve => window.setTimeout(resolve, COVER_FADE_MS));
|
|
144
|
+
overlay.remove();
|
|
145
|
+
}
|
|
130
146
|
this.overlay = undefined;
|
|
131
147
|
this.stateMachine.hidden(presentationId);
|
|
132
148
|
this.emitState();
|
package/dist/plugin.cjs.js
CHANGED
|
@@ -80,12 +80,14 @@ class SplashStateMachine {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
const PROGRESS_DELAY_MS = 1_000;
|
|
83
|
+
const COVER_FADE_MS = 500;
|
|
83
84
|
class LottieSplashWeb extends core.WebPlugin {
|
|
84
85
|
stateMachine = new SplashStateMachine();
|
|
85
86
|
playbackPromise;
|
|
86
87
|
resolvePlayback;
|
|
87
88
|
overlay;
|
|
88
89
|
progressTimer;
|
|
90
|
+
playbackTimer;
|
|
89
91
|
async show(options) {
|
|
90
92
|
const state = this.stateMachine.current();
|
|
91
93
|
if (state.visible && state.presentationId)
|
|
@@ -109,7 +111,7 @@ class LottieSplashWeb extends core.WebPlugin {
|
|
|
109
111
|
this.emitState();
|
|
110
112
|
if (!state.playbackSettled)
|
|
111
113
|
await this.waitForCompletion(options);
|
|
112
|
-
this.removeOverlay(options.presentationId);
|
|
114
|
+
await this.removeOverlay(options.presentationId);
|
|
113
115
|
}
|
|
114
116
|
async getState() {
|
|
115
117
|
const { generation: _generation, ...state } = this.stateMachine.current();
|
|
@@ -126,10 +128,14 @@ class LottieSplashWeb extends core.WebPlugin {
|
|
|
126
128
|
overlay.dataset.presentationId = presentationId;
|
|
127
129
|
Object.assign(overlay.style, {
|
|
128
130
|
position: 'fixed', inset: '0', zIndex: '2147483647', display: 'grid', placeItems: 'center',
|
|
129
|
-
background: this.backgroundFor(this.stateMachine.current().theme), overflow: 'hidden'
|
|
131
|
+
background: this.backgroundFor(this.stateMachine.current().theme), overflow: 'hidden',
|
|
132
|
+
opacity: '0', transition: `opacity ${COVER_FADE_MS}ms ease-in-out`
|
|
130
133
|
});
|
|
131
134
|
document.body.append(overlay);
|
|
132
135
|
this.overlay = overlay;
|
|
136
|
+
// Force the initial transparent style to paint before beginning the fade.
|
|
137
|
+
void overlay.offsetWidth;
|
|
138
|
+
overlay.style.opacity = '1';
|
|
133
139
|
// A generic package cannot ship HeadCount assets. The host supplies an approved local
|
|
134
140
|
// composition; absent or failed assets leave the opaque branded background in place.
|
|
135
141
|
if (!options.assets?.animationData && !options.assets?.animationPath) {
|
|
@@ -140,9 +146,13 @@ class LottieSplashWeb extends core.WebPlugin {
|
|
|
140
146
|
this.settle(presentationId, 'reduced-motion', 'Reduced motion is enabled');
|
|
141
147
|
return;
|
|
142
148
|
}
|
|
143
|
-
this.
|
|
144
|
-
|
|
145
|
-
|
|
149
|
+
this.playbackTimer = window.setTimeout(() => {
|
|
150
|
+
if (this.stateMachine.current().presentationId !== presentationId || this.overlay !== overlay)
|
|
151
|
+
return;
|
|
152
|
+
this.stateMachine.playing(presentationId);
|
|
153
|
+
this.emitState();
|
|
154
|
+
void this.playComposition(options, presentationId);
|
|
155
|
+
}, COVER_FADE_MS);
|
|
146
156
|
}
|
|
147
157
|
async playComposition(options, presentationId) {
|
|
148
158
|
try {
|
|
@@ -203,9 +213,15 @@ class LottieSplashWeb extends core.WebPlugin {
|
|
|
203
213
|
rail.append(segment);
|
|
204
214
|
this.overlay?.append(style, rail);
|
|
205
215
|
}
|
|
206
|
-
removeOverlay(presentationId) {
|
|
216
|
+
async removeOverlay(presentationId) {
|
|
207
217
|
window.clearTimeout(this.progressTimer);
|
|
208
|
-
this.
|
|
218
|
+
window.clearTimeout(this.playbackTimer);
|
|
219
|
+
const overlay = this.overlay;
|
|
220
|
+
if (overlay) {
|
|
221
|
+
overlay.style.opacity = '0';
|
|
222
|
+
await new Promise(resolve => window.setTimeout(resolve, COVER_FADE_MS));
|
|
223
|
+
overlay.remove();
|
|
224
|
+
}
|
|
209
225
|
this.overlay = undefined;
|
|
210
226
|
this.stateMachine.hidden(presentationId);
|
|
211
227
|
this.emitState();
|
package/dist/plugin.js
CHANGED
|
@@ -94,12 +94,14 @@ var capacitorLottieSplash = (function (exports, core) {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
const PROGRESS_DELAY_MS = 1_000;
|
|
97
|
+
const COVER_FADE_MS = 500;
|
|
97
98
|
class LottieSplashWeb extends core.WebPlugin {
|
|
98
99
|
stateMachine = new SplashStateMachine();
|
|
99
100
|
playbackPromise;
|
|
100
101
|
resolvePlayback;
|
|
101
102
|
overlay;
|
|
102
103
|
progressTimer;
|
|
104
|
+
playbackTimer;
|
|
103
105
|
async show(options) {
|
|
104
106
|
const state = this.stateMachine.current();
|
|
105
107
|
if (state.visible && state.presentationId)
|
|
@@ -123,7 +125,7 @@ var capacitorLottieSplash = (function (exports, core) {
|
|
|
123
125
|
this.emitState();
|
|
124
126
|
if (!state.playbackSettled)
|
|
125
127
|
await this.waitForCompletion(options);
|
|
126
|
-
this.removeOverlay(options.presentationId);
|
|
128
|
+
await this.removeOverlay(options.presentationId);
|
|
127
129
|
}
|
|
128
130
|
async getState() {
|
|
129
131
|
const { generation: _generation, ...state } = this.stateMachine.current();
|
|
@@ -140,10 +142,14 @@ var capacitorLottieSplash = (function (exports, core) {
|
|
|
140
142
|
overlay.dataset.presentationId = presentationId;
|
|
141
143
|
Object.assign(overlay.style, {
|
|
142
144
|
position: 'fixed', inset: '0', zIndex: '2147483647', display: 'grid', placeItems: 'center',
|
|
143
|
-
background: this.backgroundFor(this.stateMachine.current().theme), overflow: 'hidden'
|
|
145
|
+
background: this.backgroundFor(this.stateMachine.current().theme), overflow: 'hidden',
|
|
146
|
+
opacity: '0', transition: `opacity ${COVER_FADE_MS}ms ease-in-out`
|
|
144
147
|
});
|
|
145
148
|
document.body.append(overlay);
|
|
146
149
|
this.overlay = overlay;
|
|
150
|
+
// Force the initial transparent style to paint before beginning the fade.
|
|
151
|
+
void overlay.offsetWidth;
|
|
152
|
+
overlay.style.opacity = '1';
|
|
147
153
|
// A generic package cannot ship HeadCount assets. The host supplies an approved local
|
|
148
154
|
// composition; absent or failed assets leave the opaque branded background in place.
|
|
149
155
|
if (!options.assets?.animationData && !options.assets?.animationPath) {
|
|
@@ -154,9 +160,13 @@ var capacitorLottieSplash = (function (exports, core) {
|
|
|
154
160
|
this.settle(presentationId, 'reduced-motion', 'Reduced motion is enabled');
|
|
155
161
|
return;
|
|
156
162
|
}
|
|
157
|
-
this.
|
|
158
|
-
|
|
159
|
-
|
|
163
|
+
this.playbackTimer = window.setTimeout(() => {
|
|
164
|
+
if (this.stateMachine.current().presentationId !== presentationId || this.overlay !== overlay)
|
|
165
|
+
return;
|
|
166
|
+
this.stateMachine.playing(presentationId);
|
|
167
|
+
this.emitState();
|
|
168
|
+
void this.playComposition(options, presentationId);
|
|
169
|
+
}, COVER_FADE_MS);
|
|
160
170
|
}
|
|
161
171
|
async playComposition(options, presentationId) {
|
|
162
172
|
try {
|
|
@@ -217,9 +227,15 @@ var capacitorLottieSplash = (function (exports, core) {
|
|
|
217
227
|
rail.append(segment);
|
|
218
228
|
this.overlay?.append(style, rail);
|
|
219
229
|
}
|
|
220
|
-
removeOverlay(presentationId) {
|
|
230
|
+
async removeOverlay(presentationId) {
|
|
221
231
|
window.clearTimeout(this.progressTimer);
|
|
222
|
-
this.
|
|
232
|
+
window.clearTimeout(this.playbackTimer);
|
|
233
|
+
const overlay = this.overlay;
|
|
234
|
+
if (overlay) {
|
|
235
|
+
overlay.style.opacity = '0';
|
|
236
|
+
await new Promise(resolve => window.setTimeout(resolve, COVER_FADE_MS));
|
|
237
|
+
overlay.remove();
|
|
238
|
+
}
|
|
223
239
|
this.overlay = undefined;
|
|
224
240
|
this.stateMachine.hidden(presentationId);
|
|
225
241
|
this.emitState();
|
|
@@ -159,6 +159,7 @@ public final class LottieSplashCoordinator {
|
|
|
159
159
|
/// permanently obscure that bundle during an over-the-air/native rollout mismatch.
|
|
160
160
|
private let webAdoptionGracePeriod: TimeInterval = 10
|
|
161
161
|
private let progressDelay: TimeInterval = 1
|
|
162
|
+
private let coverFadeDuration: TimeInterval = 0.5
|
|
162
163
|
|
|
163
164
|
public private(set) var presentationId: String?
|
|
164
165
|
public private(set) var phase: LottieSplashPhase = .hidden
|
|
@@ -176,6 +177,7 @@ public final class LottieSplashCoordinator {
|
|
|
176
177
|
private var adoptionWorkItem: DispatchWorkItem?
|
|
177
178
|
private var adoptedByWeb = false
|
|
178
179
|
private var webRendererLoaded = false
|
|
180
|
+
private var coverFadeInComplete = false
|
|
179
181
|
private var progressRemaining = TimeInterval(1)
|
|
180
182
|
private var waitingClockStartedAt: Date?
|
|
181
183
|
private var playbackCompletion: ((String, String?) -> Void)?
|
|
@@ -239,7 +241,7 @@ public final class LottieSplashCoordinator {
|
|
|
239
241
|
}
|
|
240
242
|
|
|
241
243
|
public func startPlaybackIfVisible(configuration: LottieSplashConfiguration = .init()) {
|
|
242
|
-
guard phase == .preparing, animationWebView != nil else { return }
|
|
244
|
+
guard phase == .preparing, animationWebView != nil, coverFadeInComplete else { return }
|
|
243
245
|
phase = .playing
|
|
244
246
|
emitState()
|
|
245
247
|
guard !UIAccessibility.isReduceMotionEnabled else {
|
|
@@ -292,6 +294,7 @@ public final class LottieSplashCoordinator {
|
|
|
292
294
|
|
|
293
295
|
private func buildCover(in controller: UIViewController, configuration: LottieSplashConfiguration) {
|
|
294
296
|
let cover = LottieSplashCoverView(theme: configuration.resolvedTheme)
|
|
297
|
+
cover.alpha = 0
|
|
295
298
|
cover.translatesAutoresizingMaskIntoConstraints = false
|
|
296
299
|
cover.isAccessibilityElement = true
|
|
297
300
|
cover.accessibilityLabel = "Loading application"
|
|
@@ -330,6 +333,15 @@ public final class LottieSplashCoordinator {
|
|
|
330
333
|
self.animationWebView = animation
|
|
331
334
|
self.animationMessageBridge = messageBridge
|
|
332
335
|
self.webRendererLoaded = false
|
|
336
|
+
self.coverFadeInComplete = false
|
|
337
|
+
controller.view.layoutIfNeeded()
|
|
338
|
+
UIView.animate(withDuration: UIAccessibility.isReduceMotionEnabled ? 0 : coverFadeDuration, delay: 0, options: [.curveEaseInOut]) {
|
|
339
|
+
cover.alpha = 1
|
|
340
|
+
} completion: { [weak self, weak cover] _ in
|
|
341
|
+
guard let self, let cover, self.cover === cover else { return }
|
|
342
|
+
self.coverFadeInComplete = true
|
|
343
|
+
self.startPlaybackIfVisible()
|
|
344
|
+
}
|
|
333
345
|
}
|
|
334
346
|
|
|
335
347
|
private func apply(theme: LottieSplashTheme) {
|
|
@@ -439,7 +451,7 @@ public final class LottieSplashCoordinator {
|
|
|
439
451
|
adoptionWorkItem = nil
|
|
440
452
|
loadingRail?.removeFromSuperview()
|
|
441
453
|
loadingRail = nil
|
|
442
|
-
UIView.animate(withDuration: UIAccessibility.isReduceMotionEnabled ? 0 :
|
|
454
|
+
UIView.animate(withDuration: UIAccessibility.isReduceMotionEnabled ? 0 : coverFadeDuration, animations: { cover.alpha = 0 }) { [weak self] _ in
|
|
443
455
|
cover.removeFromSuperview()
|
|
444
456
|
self?.cover = nil
|
|
445
457
|
self?.phase = .hidden
|
|
@@ -447,6 +459,7 @@ public final class LottieSplashCoordinator {
|
|
|
447
459
|
self?.animationWebView?.configuration.userContentController.removeScriptMessageHandler(forName: "lottieSplash")
|
|
448
460
|
self?.animationWebView = nil
|
|
449
461
|
self?.animationMessageBridge = nil
|
|
462
|
+
self?.coverFadeInComplete = false
|
|
450
463
|
self?.emitState()
|
|
451
464
|
_ = id
|
|
452
465
|
completion(nil)
|