Skip to content
This repository was archived by the owner on Dec 19, 2021. It is now read-only.

Commit 74943a7

Browse files
authored
Merge pull request #32 from Codex-/bugfix/android_race_condition
issues/31 Fix popOver hide before display has finished operations
2 parents eed98f2 + acabd66 commit 74943a7

File tree

3 files changed

+44
-5
lines changed

3 files changed

+44
-5
lines changed

src/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export class LoadingIndicator {
22
show(options?: OptionsCommon): any;
3-
hide(): void;
3+
hide(targetView?: any, attemptTimeout?: number): void;
44
}
55

66
export interface OptionsCommon {

src/loading-indicator.android.ts

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ function useAndroidX() {
2121
return global.androidx && global.androidx.core.view;
2222
}
2323

24+
const HIDE_RETRY_MS = 100;
25+
2426
export class LoadingIndicator {
2527
private _popOver: android.widget.PopupWindow;
2628
private _currentProgressColor: Color;
@@ -30,6 +32,7 @@ export class LoadingIndicator {
3032
private _detailsId: number;
3133
private _customViewId: number;
3234
private _loadersInstances: android.widget.PopupWindow[];
35+
private _isCreatingPopOver: boolean;
3336

3437
constructor() {
3538
this._defaultProgressColor = new Color('#007DD6');
@@ -38,6 +41,7 @@ export class LoadingIndicator {
3841
this._detailsId = android.view.View.generateViewId();
3942
this._customViewId = android.view.View.generateViewId();
4043
this._loadersInstances = [];
44+
this._isCreatingPopOver = false;
4145
}
4246

4347
show(options?: OptionsCommon) {
@@ -47,18 +51,36 @@ export class LoadingIndicator {
4751
options.android = options.android || {};
4852
options.userInteractionEnabled =
4953
options.userInteractionEnabled !== undefined || true;
54+
5055
if (!this._popOver) {
51-
setTimeout(() => {
56+
this._isCreatingPopOver = true;
57+
new Promise((resolve) => {
5258
this._createPopOver(context, options);
5359
this._loadersInstances.push(this._popOver);
60+
resolve();
61+
}).then(() => {
62+
this._isCreatingPopOver = false;
63+
}).catch((error) => {
64+
// Ensure this is left in a clean state.
65+
this._isCreatingPopOver = false;
66+
const message = error && error.message ? `: ${error.message}` : '';
67+
console.error(`Error creating Loading Indicator Pop Over${message}`);
5468
});
55-
} else {
56-
this._updatePopOver(context, options);
69+
return;
5770
}
71+
this._updatePopOver(context, options);
72+
}
73+
}
74+
75+
hide(targetView?: any, attemptTimeout: number = 1000): void {
76+
if (this._isCreatingPopOver) {
77+
this._waitForCreatePopOver(attemptTimeout);
78+
return;
5879
}
80+
this._tryHide();
5981
}
6082

61-
hide() {
83+
private _tryHide(): void {
6284
try {
6385
for (let i = 0; i < this._loadersInstances.length; i++) {
6486
const loader = this._loadersInstances[i];
@@ -77,6 +99,23 @@ export class LoadingIndicator {
7799
}
78100
}
79101

102+
private _waitForCreatePopOver(attemptTimeout: number) {
103+
const startTime = Date.now();
104+
105+
const awaitCreation = async () => {
106+
if (!this._isCreatingPopOver) {
107+
return this._tryHide();
108+
}
109+
if (Date.now() > startTime + attemptTimeout) {
110+
console.warn('Hide attempt timeout exceeded');
111+
return;
112+
}
113+
await new Promise((resolve) => setTimeout(resolve, HIDE_RETRY_MS));
114+
return awaitCreation();
115+
};
116+
return awaitCreation();
117+
}
118+
80119
private _isShowing(loader: android.widget.PopupWindow) {
81120
return loader.isShowing();
82121
}
Binary file not shown.

0 commit comments

Comments
 (0)