loading screen when window opening up: Android - android

i am using the Titanium studio for developing android application. a user click on item a new window is being opened which fetch data from a site and populate the tableview. so this window does take time to open.
mean while i am fetching the data and showing loading screen like:
anotherWind.addEventListener('open', function (e) {
activityIndicator.show();
setTimeout(function(){
e.source.close();
activityIndicator.hide();
}, 6000);
});
the problem is at this point i'm assuming it takes 6 second to fetch and display a tableview. but in real time it may not be the case as time may vary depending upon the data
when user click a icon it should display the loading screen only for the time data is not pulated and showed in tableview.
its a kind of notification between two tasks. one when task is complted it should notify other one.
how can i resolve that ?

You can use a custom event listener.
Example:
Ti.App.addEventListener('tableDataLoaded', function() {
activityIndicator.hide();
}
When your table data is loaded, you fire the event:
Ti.App.fireEvent('tableDataLoaded');
I hope this will help you :)

It seems multi-thread will be a good solution.Android provide some mechanisms of communication between different threads or processes.

i have implemented the same. my new window needs to load remote data and populate the tableview.
so i just show the indicator in window open
anotherWind.addEventListener('open', function (e) {
activityIndicator.show();
});
and then hide it when my remote data is loaded. inside the callback of httpclient
'APIGetRequest(this.apiURL, function(e) {
var status = this.status;
if (status == 200) {
populatetableview(this.responseText);
activityIndicator.hide();
}
});'

Related

How to know an action is done globally react native

This is really common that i want to know an action is done and then do sth after that. for this we usually use events but i don't know how to use it in my case.
my scenario: There is an SplashScene which shows some animations for a constant time, after that time i navigate to my HomeScene. there are some other initializations which i don't want to be done unless SplashScene is gone and we r in HomeScene.
those initializations are in App component. and what im doing is that because the SplashScene animation time is constant i use a timeout to init things.
// Constants.ts
export const GlobalStaticData = {
initialDuration: 5000 // ms
}
// App
public componentDidMount() {
setTimeout(() => {
// initialize things
}, GlobalStaticData.initialDuration) // show dialogs after splash loading time
}
// SplashScene
private onAnimationEnd = () => {
NavigationActions.navigate(HomeScene)
}
but i know this is not good at all, i already experience sometimes which timing doesn't work as expected and things get initialized when app is still in SplashScene.
i was thinking for way to use events but i dont know how do that. what i want to listen to a value e.g called isSplashLoadCompleted in App component and in splash change that value when its works are done. then in App its event listener is called and initialing get started.
You can write a basic event system to subscribe to an event and then emit the event when certain thing happened on the other page:
const subscribers = {}
// Subscribe to loading your target page here Ex subsciber('home_load',()=>{ Your Logic })
const subscribe = (event,callback)=>{
if(subscribers[event] == null){ subscribers[event] = {}}
subscribers[event].push(callback)
}
const unSubscribe = (event,callback)=>{
....
}
// Call this inside your target page componentDidMount Ex: emitEvent('home_load',Some data or null)
const emitEvent = (event,data)=>{
if(subscribers[event]!=null && subscibers[event].length > 0){
for(const cb of subscribers[event]){
if(cb != null){cb()}
}
}
}
Sounds like the you want to trigger specific code when different scenes are loaded. I would recommend moving your animation/initialization logic into the compomentDidMount() for the respective scenes - SplashScene and HomeScene.
You're running into issues because your animation/initialization code is completely decoupled from your scenes. Couple the logic to the componentDidMount for these scenes and you won't have to worry about timing issues.

Android Back Button on a Progressive Web Application closes de App

Can a "pure" HTML5/Javascript (progressive) web application intercept the mobile device back button in order to avoid the App to exit?
This question is similar to this one but I want to know if it is possible to achieve such behavior without depending on PhoneGap/Ionic or Cordova.
While the android back button cannot be directly hooked into from within a progressive web app context, there exists a history api which we can use to achieve your desired result.
First up, when there's no browser history for the page that the user is on, pressing the back button immediately closes the app.
We can prevent this by adding a previous history state when the app is first opens:
window.addEventListener('load', function() {
window.history.pushState({}, '')
})
The documentation for this function can be found on mdn:
pushState() takes three parameters: a state object, a title (which is currently ignored), and (optionally) a URL[...] if it isn't specified, it's set to the document's current URL.
So now the user has to press the back button twice. One press brings us back to the original history state, the next press closes the app.
Part two is we hook into the window's popstate event which is fired whenever the browser navigates backwards or forwards in history via a user action (so not when we call history.pushState).
A popstate event is dispatched to the window each time the active history entry changes between two history entries for the same document.
So now we have:
window.addEventListener('load', function() {
window.history.pushState({}, '')
})
window.addEventListener('popstate', function() {
window.history.pushState({}, '')
})
When the page is loaded, we immediately create a new history entry, and each time the user pressed 'back' to go to the first entry, we add the new entry back again!
Of course this solution is only so simple for single-page apps with no routing. It will have to be adapted for applications that already use the history api to keep the current url in sync with where the user navigates.
To do this, we will add an identifier to the history's state object. This will allow us to take advantage of the following aspect of the popstate event:
If the activated history entry was created by a call to history.pushState(), [...] the popstate event's state property contains a copy of the history entry's state object.
So now during our popstate handler we can distinguish between the history entry we are using to prevent the back-button-closes-app behaviour versus history entries used for routing within the app, and only re-push our preventative history entry when it specifically has been popped:
window.addEventListener('load', function() {
window.history.pushState({ noBackExitsApp: true }, '')
})
window.addEventListener('popstate', function(event) {
if (event.state && event.state.noBackExitsApp) {
window.history.pushState({ noBackExitsApp: true }, '')
}
})
The final observed behaviour is that when the back button is pressed, we either go back in the history of our progressive web app's router, or we remain on the first page seen when the app was opened.
#alecdwm, that is pure genius!
Not only does it work on Android (in Chrome and the Samsung browser), it also works in desktop web browsers. I tested it on Chrome, Firefox and Edge on Windows, and it's likely the results would be the same on Mac. I didn't test IE because eew. Even if you're mostly designing for iOS devices that have no back button, it's still a good idea to ensure that Android (and Windows Mobile... awww... poor Windows Mobile) back buttons are handled so that the PWA feels much more like a native app.
Attaching an event listener to the load event didn't work for me, so I just cheated and added it to an existing window.onload init function I already had anyhow.
Keep in mind that it might frustrate users who would actually want to really Go Back to whatever web page they were looking at before navigating to your PWA while browsing it as a standard web page. In that case, you can add a counter and if the user hits back twice, you can actually allow the "normal" back event to happen (or allow the app to close).
Chrome on Android also (for some reason) added an extra empty history state, so it took one additional Back to actually go back. If anyone has any insight on that, I'd be curious to know the reason.
Here's my anti-frustration code:
var backPresses = 0;
var isAndroid = navigator.userAgent.toLowerCase().indexOf("android") > -1;
var maxBackPresses = 2;
function handleBackButton(init) {
if (init !== true)
backPresses++;
if ((!isAndroid && backPresses >= maxBackPresses) ||
(isAndroid && backPresses >= maxBackPresses - 1)) {
window.history.back();
else
window.history.pushState({}, '');
}
function setupWindowHistoryTricks() {
handleBackButton(true);
window.addEventListener('popstate', handleBackButton);
}
This approach has a couple of improvements over existing answers:
Allows the user to exit if they press back twice within 2 seconds: The best duration is debatable but the idea of allowing an override option is common in Android apps so it's often the correct approach.
Only enables this behaviour when in standalone (PWA) mode: This ensures the website keeps behaving as the user would expect when within an Android web browser and only applies this workaround when the user sees the website presented as a "real app".
function isStandalone () {
return !!navigator.standalone || window.matchMedia('(display-mode: standalone)').matches;
}
// Depends on bowser but wouldn't be hard to use a
// different approach to identifying that we're running on Android
function exitsOnBack () {
return isStandalone() && browserInfo.os.name === 'Android';
}
// Everything below has to run at page start, probably onLoad
if (exitsOnBack()) handleBackEvents();
function handleBackEvents() {
window.history.pushState({}, '');
window.addEventListener('popstate', () => {
//TODO: Optionally show a "Press back again to exit" tooltip
setTimeout(() => {
window.history.pushState({}, '');
//TODO: Optionally hide tooltip
}, 2000);
});
}
i did not want to use native javascript functions to handle this inside of a react app, so i scoured solutions
that used react-router or react-dom-router, but in the end, up against a deadline, native js is
what got it working. Added the following listeners inside inside componentDidMount() and setting the history
to an empty state
window.addEventListener('load', function() {
window.history.pushState({}, '')
})
window.addEventListener('popstate', function() {
window.history.pushState({}, '')
})
this worked fine on the browser, but was still not working in the PWA on mobile
finally a colleague found out that triggering the history actions via code is what somehow initiated the listeners
and voila! everything fell in place
window.history.pushState(null, null, window.location.href);
window.history.back();
window.history.forward();
In my case, I had a SPA with different drawers on that page and I want them to close when User hits back button..
you can see different drawers in the image below:
I was managing states(eg open or close) of all drawers at a central location (Global state),
I added the followin code to a useEffect hook that runs only once on loading of web app
// pusing initial state on loading
window.history.pushState(
{ // Initial states of drawers
bottomDrawer,
todoDetailDrawer,
rightDrawer,
},
""
);
window.addEventListener("popstate", function () {
//dispatch to previous drawer states
// dispatch will run when window.history.back() is executed
dispatch({
type: "POP_STATE",
});
});
and here is what my dispatch "POP_STATE" was doing,
if (window.history.state !== null) {
const {
bottomDrawer,
rightDrawer,
todoDetailDrawer,
} = window.history.state; // <- retriving state from window.history
return { // <- setting the states
...state,
bottomDrawer,
rightDrawer,
todoDetailDrawer,
};
It was retriving the last state of drawers from window.history and setting it to current state,
Now the last part, when I was calling window.history.pushState({//object with current state}, "title", "url eg /RightDrawer") and window.history.back()
very simple,
window.history.pushState({//object with current state}, "title", "url eg /RightDrawer") on every onClick that opens the drawer
&
window.history.back() on every action that closes the drawer.

I am trying to make an application that will make phone calls one after another from the list of number

I am developing an application for my friend who is in sales, this application will make phone calls one after another, as soon as one phone call gets disconnected, it will automatically make call to another number from the list. This list can be read from and xml data source or json or mongodb or even from excel sheet.
This could be an ios app that reads data from an end point and stores them and can initiate the call at any point and it wont stop until all the calls are made.
Next call will be made only after the first call has been finished.
I am thinking about using node based web app using google voice to trigger the chain.
I've no experience with ios / android apis but Im willing to work on that if it's a viable thing on that platform.
Note: what we're trying to avoid is whole process of
looking up the phone number.
touch hangup and then click for another phone number.
It should self trigger the next call as soon as current call gets disconnected.
Also we're trying to avoid any paid services like twillo.
Thanks in advance :)
for IOS, you could use CTCallCenter
self.callCenter = [[CTCallCenter alloc] init];
self.callCenter.callEventHandler = ^(CTCall *call){
if ([call.callState isEqualToString: CTCallStateConnected])
{
//NSLog(#"call stopped");
}
else if ([call.callState isEqualToString: CTCallStateDialing])
{
}
else if ([call.callState isEqualToString: CTCallStateDisconnected])
{
//NSLog(#"call played");
}
else if ([call.callState isEqualToString: CTCallStateIncoming])
{
}
};
Download phone list, loop inside phone list, make a call, listening for CTCallCenter and appdelegate's Event, detect user have finish last call, our app active again, then make the next call.
Or you can try in Demo here !

android phonegap custom "Web page not found"

Problem:
I'm trying to avoid the "web page not found", or at least to display a customized error page.
Context:
I use the cordova trick:
if (navigator.network.connection.type == Connection.NONE)
{
window.location="offline/index.html";
}
else
{
window.location="http://myurl.com";
}
But in my tablet, if there's no connection, I have the ugly "WebPage not found".
There's maybe something wrong in my code, but in all case I would like to find a way to avoid this page and to show my own.
I will be very happy if somebody here can tell me where to give a look.
Stef
PS : the "Page Not found" appears when the website is down. It's not related to the event offline. You can have internet, and the server can be down. In that case, I want to display my own error page. Thanks!
There is an event offline available in Cordova. You could add event listeners to this and do required changes in its callback. If you are using deviceready event it will be called only once when your app is done loading. But if you add offline & online listeners you can alert user each time network goes down/up.
document.addEventListener("offline", onOffline, false);
function onOffline() {
// Handle the offline event
}
http://docs.phonegap.com/en/2.9.0/cordova_events_events.md.html#offline

Fire Event execute multiple time. titanium android

I am developing android application with Titanium, android sdk 1.8.0.1.In my application there are three tabs.Every Time when I click on tab my window get refreshed.So my code structure looks like:
////// on tab click /////////////////////
var explore = Titanium.UI.createWindow(
{
//navBarHidden:true,
backgroundColor:'#f8f8f8'
});explore.open({animated:true});
////// m.js /////////////////
var explore = Titanium.UI.currentWindow;
Ti.App.addEventListener('feed_partial_action',function(e)
{
alert('inside event')
})
var new = Titanium.UI.createButton(
{
});explore.add(new);
new.addEventListener('click', function(e)
{
var explore_new = Titanium.UI.createWindow(
{
navBarHidden:true,
backgroundColor:'#f8f8f8'
});explore_new.open({animated:true});
});
/////// explore_new.js/////////////////
var explore_new = Titanium.UI.currentWindow;
Ti.App.fireEvent('feed_partial_action',{page_type:'new'});
so my problem is that on first load alert inside the event listner in m.js executed once but when I again call m.js it shows alert twice.on third time it shows alert 3 times and so on and after some time it forcefully close the app.I think event listener of window still open after refreshing widow.So is there any way to handle this problem.Thank you
What you have here is a memory leak.
When you add the event listener to Ti.App with the statement
Ti.App.addEventListener('feed_partial_action',function(e)
{
alert('inside event')
});
That anonymous function is stored within the Ti.App context (it has to retain a reference to the function so that it can invoke it when the "feed_partial_action" event is fired). That function will not be garbage collected until Ti.App releases its reference to it. Furthermore, it remains tied to the event.
There are several ways to deal with this. I don't know exactly how to tell you how to fix your problem because I don't have a lot of context with the provided code sample. So, here are some solutions. If one of the assumptions below is not correct, please give more detail.
If the 'feed_partial_action' event is truly supposed to be global event that has one and only one event handler, move
Ti.App.addEventListener('feed_partial_action',function...); code outside a block that gets executed multiple times.
If you need to stop receiving the event when the explore window is closed, then move the eventHandler function (the anonymous one) out to a named function or variable and call Ti.App.removeEventListener('feed_partial_action', myFunction); when you close the window. The easiest way to do this would be
function feedPartialActionCB(e) { alert('inside event'); }
Ti.App.addEventListener('feed_partial_action', feedPartialActionCB);
explore.addEventListener('close', function() {
Ti.App.removeEventListener('feed_partial_action', feedPartialActionCB);
});

Categories

Resources