Created
May 28, 2019 11:41
-
-
Save hansemannn/20297e983e2b8c898975b600e7ab8418 to your computer and use it in GitHub Desktop.
A cross platform modal loading indicator to use in Appcelerator Titanium
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import TiAnimation from 'ti.animation'; | |
/** | |
* A loader class to show a modal loading indicator | |
* above the current context (even above modal). | |
* | |
* Author: Hans Knöchel | |
* | |
*/ | |
export default class Loader { | |
/** | |
* The constructor of the loading indicator. It | |
* configures the native API's based on the platform. | |
* @param {Object} options The options passed to the loader. | |
* @param {String} options.view The view to show on the loader (optional). | |
* @param {String} options.title The title to show on the loader (optional). | |
*/ | |
constructor(options = {}) { | |
this.view = !this.isAndroid ? Ti.UI.createWindow() : undefined; | |
this.title = options.title || L('loading_progress'); | |
this.viewBased = options.view !== undefined && options.view != null; | |
if (options.view) { | |
this.view = options.view; | |
} | |
if (this.isAndroid) { | |
this.activityIndicator = Ti.UI.Android.createProgressIndicator({ | |
message: this.title, | |
location: Ti.UI.Android.PROGRESS_INDICATOR_DIALOG, | |
type: Ti.UI.Android.PROGRESS_INDICATOR_INDETERMINANT, | |
cancelable: false | |
}); | |
} else { | |
this.activityIndicator = TiAnimation.createAnimationView({ | |
file: '/animations/spinner.json', | |
loop: true, | |
autoStart: true, | |
top: 28, | |
width: 65, | |
height: 65 | |
}); | |
this.containerView = Ti.UI.createView({ backgroundColor: '#55000000', visible: false }); | |
const indicatorView = Ti.UI.iOS.createBlurView({ | |
effect: Ti.UI.iOS.BLUR_EFFECT_STYLE_LIGHT, | |
width: 200, | |
height: 150, | |
borderRadius: 20 | |
}); | |
const label = Ti.UI.createLabel({ | |
text: this.title, | |
top: 100, | |
width: 160, | |
textAlign: 'center', | |
height: Ti.UI.SIZE, | |
font: { | |
fontFamily: Alloy.CFG.fonts.sourceSansPro.semibold, | |
fontSize: 15 | |
}, | |
color: '#000' | |
}); | |
indicatorView.add(this.activityIndicator); | |
indicatorView.add(label); | |
this.containerView.add(indicatorView); | |
this.view.add(this.containerView); | |
} | |
} | |
/** | |
* A utility getter to determine if we are on Android or not. | |
* | |
* @return {Boolean} Whether or not the current process runs on Android or not. | |
*/ | |
get isAndroid() { | |
return Ti.Platform.osname === 'android'; | |
} | |
/** | |
* Shows the loader. On iOS, it uses a animation to fade in | |
* the parent view before showing the actual loader. | |
*/ | |
show() { | |
return new Promise((resolve, _reject) => { | |
if (!this.isAndroid) { | |
if (this.viewBased) { | |
this.view.add(this.containerView); | |
resolve(); | |
} else { | |
this.showResolveCallback = resolve; | |
this.view.navBarHidden = true; | |
this.navigationWindow = Ti.UI.createNavigationWindow({ | |
window: this.view | |
}); | |
this.view.addEventListener('open', () => { this._handleOpen(); }); | |
this.view.addEventListener('close', () => { this._handleClose(); }); | |
// Using this navigation window config, we can even show loaders above modal windows | |
this.navigationWindow.open({ | |
modal: true, | |
modalStyle: Ti.UI.iOS.MODAL_PRESENTATION_OVER_CURRENT_FULL_SCREEN, | |
modalTransitionStyle: Ti.UI.iOS.MODAL_TRANSITION_STYLE_CROSS_DISSOLVE, | |
animated: false | |
}); | |
} | |
this.containerView.visible = true; | |
} else { | |
this.activityIndicator.show(); | |
resolve(); | |
} | |
}); | |
} | |
/** | |
* Hides the loader. On iOS, it uses a animation to fade out | |
* the parent view before hiding the actual loader. | |
*/ | |
hide() { | |
return new Promise((resolve, _reject) => { | |
if (!this.isAndroid) { | |
if (this.viewBased) { | |
this.view.remove(this.containerView); | |
resolve(); | |
} else { | |
this.hideResolveCallback = resolve; | |
setTimeout(() => { | |
this.navigationWindow.close({ animated: false }); | |
}, 500); | |
} | |
} else { | |
this.activityIndicator.hide(); | |
resolve(); | |
} | |
}); | |
} | |
_handleClose() { | |
if (this.hideResolveCallback) { | |
this.hideResolveCallback(); | |
this.hideResolveCallback = null; | |
} | |
} | |
_handleOpen() { | |
if (this.showResolveCallback) { | |
this.showResolveCallback(); | |
this.showResolveCallback = null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment