Ionic 4 app - detect if user turns off or on gps - ionic4

I would like to know how I can do to detect if during any moment of the execution of an Ionic 4 app (not only at the beginning of the app), the user manually turns off or on the GPS.
What Ionic 4 event can I hear from the GPS, to be able to alert at any time of the execution of the app if the user turned off or on the GPS?
Thank you very much and sorry for my bad English
My code on app.component.ts:
initializeApp() {
this.platform.ready().then(() => {
this.screenOrientation.lock(this.screenOrientation.ORIENTATIONS.PORTRAIT_PRIMARY);
this.platform.backButton.subscribeWithPriority(9999, () => {
document.addEventListener('backbutton', function (event) {
event.preventDefault();
event.stopPropagation();
}, false);
this.presentAlertConfirm();
});
this.geolocation.getCurrentPosition().then((resp) => {
this.global.origin = { lat: resp.coords.latitude, lng: resp.coords.longitude };
this.global.latitude = resp.coords.latitude;
this.global.longitude = resp.coords.longitude;
}).catch((error) => {
console.log('Error getting location', error);
});
let watch = this.geolocation.watchPosition();
watch.subscribe((data) => {
this.global.origin = { lat: data.coords.latitude, lng: data.coords.longitude };
this.global.latitude = data.coords.latitude;
this.global.longitude = data.coords.longitude;
}, error => {
console.log('Error getting location in WATCH', error); //error handling //
})
this.statusBar.styleDefault();
this.splashScreen.hide();
});
}

You have to watch for some GPS change. As proposed in the Ionic 4 documentation and as you have done correctly:
this.watch = this.geolocation.watchPosition();
this.watch.subscribe((data) => {
// usable data
}, (error) => {
// some error
}, { timeout: 30000 });
timeout: The maximum length of time (milliseconds) that is allowed to pass without receiving a set of coordinates.
And remeber to unsubscribe on destroy:
public ngOnDestroy(): void {
this.watch.unsubscribe();
}

Related

React-Native-Image-Picker Auto video recording possible?

I'm a beginner at React Native.
I am trying to access a native(built-in) camera app on Android device.
I used React-Native-Image-Picker to open the camera app but I would like to record a video somehow automatically(?) I mean not using my finger.
I need codes that make it to record and stop the video.
(I don't mean to give me a code rather, please advise if it is even possible?)
Any help would be very appreciated.
Thank you!
It is possible.
Package: https://github.com/mrousavy/react-native-vision-camera
Review the API and Guide section to see how to start and stop recording programmatically.
They also show an example app that demonstrates different types of capture including video recording, ref: https://github.com/mrousavy/react-native-vision-camera/blob/28fc6a68a5744efc85b532a338e2ab1bc8fa45fe/example/src/views/CaptureButton.tsx
...
const onStoppedRecording = useCallback(() => {
isRecording.current = false;
cancelAnimation(recordingProgress);
console.log('stopped recording video!');
}, [recordingProgress]);
const stopRecording = useCallback(async () => {
try {
if (camera.current == null) throw new Error('Camera ref is null!');
console.log('calling stopRecording()...');
await camera.current.stopRecording();
console.log('called stopRecording()!');
} catch (e) {
console.error('failed to stop recording!', e);
}
}, [camera]);
const startRecording = useCallback(() => {
try {
if (camera.current == null) throw new Error('Camera ref is null!');
console.log('calling startRecording()...');
camera.current.startRecording({
flash: flash,
onRecordingError: (error) => {
console.error('Recording failed!', error);
onStoppedRecording();
},
onRecordingFinished: (video) => {
console.log(`Recording successfully finished! ${video.path}`);
onMediaCaptured(video, 'video');
onStoppedRecording();
},
});
// TODO: wait until startRecording returns to actually find out if the recording has successfully started
console.log('called startRecording()!');
isRecording.current = true;
} catch (e) {
console.error('failed to start recording!', e, 'camera');
}
}, [camera, flash, onMediaCaptured, onStoppedRecording]);
//#endregion
...

Clear the app data if disconnected from internet for more then 5min in react native

I want to clear the react native app data if my app is disconnected from internet for more than 5 min.
I am using react native NetInfo to check network connectivity status.
Saving the time when app disconnected and checking when it will reconnect to internet.
If interval is more than 5 min then I want to clear the app data.
My Code is:
class OfflineMessage extends PureComponent {
constructor(props) {
super(props);
this.state = {
isConnected: true
};
}
componentDidMount() {
NetInfo.addEventListener((state) => {
this.handleConnection(state.isConnected);
});
}
componentWillUnmount() {
NetInfo.removeEventListener((state) => {
this.handleConnection(state.isConnected);
});
}
handleConnection = (isConnected) => {
this.setState({ isConnected });
if(!isConnected){
this.startTimer();
} else {
this.checkElapsed();
}
};
startTimer = async () => {
try {
console.log('Internet disconnected at: ');
await AsyncStorage.setItem('time', JSON.stringify(Date.now()));
} catch (error) {
// console.log('Something went wrong', error);
}
}
checkElapsed = async () => {
try {
let startTime = await AsyncStorage.getItem('time');
if(startTime){
let endTime = Date.now();
const elapsedTime = Math.floor((endTime -JSON.parse(startTime))/1000);
if(elapsedTime > 5){
alert("5 min is completed.");
// Clear app data
}
console.log('Time elapsed'+ elapsedTime);
}
} catch (error) {
// console.log('Something went wrong', error);
}
}
Problem:
Both the methods startTimer and checkElapsed called whenever connectivity status changes.
What is wrong with this code.
if I modify given code as :
state = {
isConnected: true
};
componentDidMount() {
this.unsubscribeFromNetInfo = NetInfo.addEventListener((state) => {
this.handleConnection(state.isConnected);
});
}
componentWillUnmount() {
this.unsubscribeFromNetInfo();
}
handleConnection = (isConnected) => {
console.log(isConnected);
this.setState({ isConnected });
};
EventListener called multiple times and status changes frequently true false,true,false .
Now, you are handling the NetInfo subscription wrong, according to https://github.com/react-native-community/react-native-netinfo#usage
You would have to do:
componentDidMount() {
this.unsubscribeFromNetInfo = NetInfo.addEventListener(state => {
this.handleConnection(state.isConnected);
});
}
componentWillUnmount() {
this.unsubscribeFromNetInfo();
}
Also, if you want to check for 5 minutes use:
if (elapsedTime > 5 * 60)
as your conversion
Math.floor((endTime - JSON.parse(startTime)) / 1000)
converts it to seconds not minutes.
In the current state, your app will trigger almost everything as the code only checks for 5 seconds.
Otherwise, the logic that you implemented itself should be working :)

Deep links in react-native-firebase notifications

I am using react-native-firebase with messaging to deliver notifications to my app with cloud functions, with admin.messaging().send(message), very similar to here: https://medium.com/the-modern-development-stack/react-native-push-notifications-with-firebase-cloud-functions-74b832d45386 .
I receive notifications when the app is in the background. Right now I am sending a text in the body of the notification, like 'a new location has been added to the map'. I want to be able to add some sort of deep link, so that when I swipe View on the notification (on iOS for example), it will take me to a specific screen inside the app. How do I pass data from the notification to the app?
I am using react-native-navigation in the app. I can only find code about deep links from inside the app (https://wix.github.io/react-native-navigation/#/deep-links?id=deep-links).
My solution was to use add what information I need in the data object of the notification message object:
in functions/index.js:
let message = {
notification: {
body: `new notification `
},
token: pushToken,
data: {
type: 'NEW_TRAINING',
title: locationTitle
}
};
and process as follows in the app for navigation:
this.notificationOpenedListener =
firebase.notifications().onNotificationOpened((notificationOpen: NotificationOpen) => {
if (notification.data.type === 'NEW_TRAINING') {
this.props.navigator.push({
screen: 'newtrainingscreen',
title: notification.data.title,
animated: true
});
}
I think you are fine with the "how firebase notification work"... cause of this, here is only an description of the Logic how you can Deeplinking into your App.
If you send a notification, add a data-field. Let's say your app has a Tab-Navigator and the sections "News","Service" and "Review".
In your Push-Notification - Datafield (let's name it "jumpToScreen" you define your value:
jumpToScreen = Service
I assume you still have the Handling to recieve Notifications from Firebase implemented.
So create an /lib/MessageHandler.js Class and put your business-logic inside.
import firebase from 'react-native-firebase';
/*
* Get a string from Firebase-Messages and return the Screen to jump to
*/
const getJumpPoint = (pointer) => {
switch (pointer) {
case 'News':
return 'NAV_NewsList'; // <= this are the names of your Screens
case 'Service':
return 'NAV_ServiceList';
case 'Review':
return 'NAV_ReviewDetail';
default: return false;
}
};
const MessageHandler = {
/**
* initPushNotification initialize Firebase Messaging
* #return fcmToken String
*/
initPushNotification: async () => {
try {
const notificationPermission = await firebase.messaging().hasPermission();
MessageHandler.setNotificationChannels();
if (notificationPermission) {
try {
return await MessageHandler.getNotificationToken();
} catch (error) {
console.log(`Error: failed to get Notification-Token \n ${error}`);
}
}
} catch (error) {
console.log(`Error while checking Notification-Permission\n ${error}`);
}
return false;
},
clearBadges: () => {
firebase.notifications().setBadge(0);
},
getNotificationToken: () => firebase.messaging().getToken(),
setNotificationChannels() {
try {
/* Notification-Channels is a must-have for Android >= 8 */
const channel = new firebase.notifications.Android.Channel(
'app-infos',
'App Infos',
firebase.notifications.Android.Importance.Max,
).setDescription('General Information');
firebase.notifications().android.createChannel(channel);
} catch (error) {
console.log('Error while creating Push_Notification-Channel');
}
},
requestPermission: () => {
try {
firebase.messaging().requestPermission();
firebase.analytics().logEvent('pushNotification_permission', { decision: 'denied' });
} catch (error) {
// User has rejected permissions
firebase.analytics().logEvent('pushNotification_permission', { decision: 'allowed' });
}
},
foregroundNotificationListener: (navigation) => {
// In-App Messages if App in Foreground
firebase.notifications().onNotification((notification) => {
MessageHandler.setNotificationChannels();
navigation.navigate(getJumpPoint(notification.data.screen));
});
},
backgroundNotificationListener: (navigation) => {
// In-App Messages if App in Background
firebase.notifications().onNotificationOpened((notificationOpen) => {
const { notification } = notificationOpen;
notification.android.setChannelId('app-infos');
if (notification.data.screen !== undefined) {
navigation.navigate(getJumpPoint(notification.data.screen));
}
});
},
appInitNotificationListener: () => {
// In-App Messages if App in Background
firebase.notifications().onNotificationOpend((notification) => {
notification.android.setChannelId('app-infos');
console.log('App-Init: Da kommt ne Message rein', notification);
firebase.notifications().displayNotification(notification);
});
},
};
export default MessageHandler;
In your index.js you can connect it like this:
import MessageHandler from './lib/MessageHandler';
export default class App extends Component {
state = {
loading: null,
connection: null,
settings: null,
};
async componentDidMount() {
const { navigation } = this.props;
await MessageHandler.initPushNotification();
this.notificationForegroundListener = MessageHandler.foregroundNotificationListener(navigation);
this.notificationBackgroundListener = MessageHandler.backgroundNotificationListener(navigation);
this.setState({ loading: false, data });
}
componentWillUnmount() {
this.notificationForegroundListener();
this.notificationBackgroundListener();
}
async componentDidMount() {
MessageHandler.requestPermission();
AppState.addEventListener('change', this.handleAppStateChange);
MessageHandler.clearBadges();
}
componentWillUnmount() {
AppState.removeEventListener('change', this.handleAppStateChange);
}
handleAppStateChange = (nextAppState) => {
if (nextAppState.match(/inactive|background/)) {
MessageHandler.clearBadges();
}
....
I hope this give you an Idea how to implement it for your needs.
I think you don't need to use deep links nor dynamic links but just use Firebase/Notifications properly. If I were you I would add the following logic in the componentDidMount method of your parent container:
async componentDidMount() {
// 1. Check notification permission
const notificationsEnabled = await firebase.messaging().hasPermission();
if (!notificationsEnabled) {
try {
await firebase.messaging().requestPermission(); // Request notification permission
// At this point the user has authorized the notifications
} catch (error) {
// The user has NOT authorized the notifications
}
}
// 2. Get the registration token for firebase notifications
const fcmToken = await firebase.messaging().getToken();
// Save the token
// 3. Listen for notifications. To do that, react-native-firebase offer you some methods:
firebase.messaging().onMessage(message => { /* */ })
firebase.notifications().onNotificationDisplayed(notification => { /* */ })
firebase.messaging().onNotification(notification => { /* */ })
firebase.messaging().onNotificationOpened(notification => {
/* For instance, you could use it and do the NAVIGATION at this point
this.props.navigation.navigate('SomeScreen');
// Note that you can send whatever you want in the *notification* object, so you can add to the notification the route name of the screen you want to navigate to.
*/
})
}
You can find the documentation here: https://rnfirebase.io/docs/v4.3.x/notifications/receiving-notifications

Pusher Chatkit in Vue - onNewMessage hook triggered twice?

I have a Vue.js application using the Pusher Chatkit.
I have a problem I haven't been able to find an answer for some time now.
Whenever I re-visit a view/component the Chatkit onNewMessage() hook is triggered multiple times. It depends on the times I re-visit the page.
Page refresh or first-time load resolves the issue until next re-visit.
It must be that I am creating multiple listeners each time I visit the view, but I don't get what these listeners are.
Pusher states that room subscriptions "override" the old ones when done twice.
Here is my chat.vue component
import chatConnection from '../chatkit.js'
created(){
let chatManagerConnectPromise = chatConnection(this, uid)
Promise.all([..., chatManagerConnectPromise, ...])
.then(results => {
// ...
this.initiateNewChatState(results[1])
// ...
})
.catch(error =>{
});
},
methods: {
initiateNewChatState(currentUser){
this.subscribeToAllUserRooms(currentUser)
},
subscribeToAllUserRooms(currentUser){
for(let room of currentUser.rooms){
this.subscribeToRoom(currentUser, room.id)
}
},
subscribeToRoom(currentUser, roomId){
currentUser.subscribeToRoom({
roomId: roomId,
hooks: {
onNewMessage: message => {
console.log("CHAT | onNewMessage | new: ", message.text)
}
},
messageLimit: 10
})
.catch(error => {
this.notifyError("Uh oh", "Something is not right")
});
}
}
And here is my chatkit.js content:
import { ChatManager, TokenProvider } from '#pusher/chatkit'
export const chatConnection = ({ state, actions }, uid) =>{
return new ChatManager({
instanceLocator: "##:###:###:####:####",
userId: uid,
tokenProvider: new TokenProvider({url: 'https://...' })
})
.connect({
onAddedToRoom: room => {
// some action taken
},
onRemovedFromRoom: room => {
// some action taken
},
onRoomDeleted: room => {
// some action taken
}
})
.then(user => {
return user
})
.catch(error => console.log('CHATKIT | Error on connection', error))
}
Again, the problem is that the onNewMessage() is triggered once the first time after the page refresh/first load, but then increases by one with each new page visit (back and forth navigation).
I am creating some listeners with each visit but it cannot be the ChatManager not the User.subscribeToRoom!?
Thanks for any pointers.

Private channel works with static id but not dynamic vue.js

On private channel when i hard coded the ID it works fine and i m receiving messages but when set the value to Dynamic it won't work.
Here is my app.js code
const livechat = new Vue({
el: '#livechat',
data: {
conversation: [],
},
methods: {
addMessage(message) {
// Add to existing messages
// this.conversation.messages.push(message);
// Persist to the database etc
axios.post('/messages', message).then(response => {
this.conversation.messages.push(response.data);
})
}
},
created() {
axios.get('/messages/' + user_id).then(response => {
this.conversation = response.data;
});
Echo.private('chat.' + this.conversation.conversation_id)
.listen('MessageSent', (e) => {
this.conversation.messages.push({
conversation_id: e.message.conversation_id,
message: e.message.message,
name: e.user.firstname
});
});
}
});
On console log i m receving the conversation_id = 22
Echo.private('chat.22') //This works fine
Echo.private('chat.' + this.conversation.conversation_id) //This won't working
Broadcast file
public function broadcastOn()
{
return new PrivateChannel('chat.' . (int)$this->message->conversation_id);
}
Is there any thing wrong in my code. Your help will be appreciated. Thanks
The Echo.private call should be done only when you have all the data - in other words, within axios.get().then(...):
axios.get('/messages/' + user_id).then(response => {
this.conversation = response.data;
Echo.private('chat.' + this.conversation.conversation_id)
.listen('MessageSent', (e) => {
this.conversation.messages.push({
conversation_id: e.message.conversation_id,
message: e.message.message,
name: e.user.firstname
});
});
});