Make countdown in background task on ios react-native - javascript

Right now I have this in my componentDidMount() methode:
setInterval(() => this.getTimeUntil(getTheTimeToAdd, count++), 1000);
It calls another methode for updating every second to count down. I have a problem when the user is counting down the application might close or the iPhone goes to sleep.
I have tried to use both:
react-native-mauron85-background-geolocation
and:
react-native-background-timer
To keep the count down running even when the iPhone sleeps og the application is closed. Any suggestions?

What you can do is create new Dates for each invocation to see the elapsed time. Like
setInterval(function() {
Date d = new Date();
if (this.oldDate && this.oldDate.getTime() + DELAY_THRESHHOLD < d.getTime()) {
...
this.oldDate = d;
}
else {
... //should anything be here?
}
},500);

Since you're already using react-native-background-timer,
you can use the setInterval from the BackgroundTimer instance.
Assuming that you've linked the project correctly, you should be able to do
// In the constructor or the state
this.state = {
initialCounter: 120000, //Equivalents to 2 minutes
active: false, // To show or hide a label
}
componentWillMount() {
this.setIntervalId = BackgroundTimer.setInterval(() => {
if (this.state.initialCounter === 0) {
this.setState({
initialCounter: this.state.initialCounter,
active: true,
})
} else {
this.setState({
initialCounter: this.state.initialCounter - 1000,
active: false,
})
}
}, 1000)
}
// Make sure to unmount the listener when component unmounts
componentWillUnmount() {
BackgroundTimer.clearInterval(this.setIntervalId)
}
// Helper func to reinitiate the counter
_onUpdate = () => {
this.setState({ initialCounter: 120000, active: false })
}
// And inside your render you may display the timer by formatting with moment()
The docs are a bit misleading, since setInterval and clearInterval works on IOS too. Tested on package 2.0.1

Try this code, it should catch up every time the app wakes up.
const duration = 15; // duration in minute
const alertAt = Date.now() + duration * 60 * 1000;
const interval = setInterval(() => {
const remaining = alertAt - Date.now();
if (remaining < 0) {
// time is up
clearInterval(interval);
return;
}
console.log(remaining);
}, 10)

Related

JS/React - Components lose touch functionality when passed through useEffect/setInterval?

I am making a simple space shooter style game. The bad guys will be sent to the screen in intervals (similar to tetris).
The bad guys have all their touch functionality working when I pass them in an array manually but when I try to send them to the screen in intervals they lose all touch functionality.
I first tried a useEffect hook with setInterval. The interval would filter the array of bad guys. That was where the problem first popped up. Then, I tried a custom useInterval hook and got the same result.
Lastly - rather than set the state of the array of onscreen villains, I thought I would keep the villains out of the setInterval and just increment indexes, and return a slice of them. This did allow the first villain to gain touch ability but ... I was again frustrated by failure.
Here is the offending code -
aliensArray is the array of alien components for the user to battle.
function runTheInterval(){
const difference = slice.right - slice.left;
if(slice.right < aliensArray.length-1){
slice.right += 1;
}
if (slice.left < slice.right && difference > 3 && difference < 5){
slice.left += 1;
}else if (slice.left < slice.right && slice.right === aliensArray.length-1){
slice.left += 1;
}
setSlice(() => {
return { right: slice.right, left: slice.left }
})
}
const interValue = useInterval(runTheInterval, 4000);
----Other code----
const liveOnScreen = aliensArray.slice(slice.left, slice.right);
<>
{liveOnScreen}</>
So the only thing to pass through the interval is the indices of the villains array to be filtered. What am I doing wrong??
Thanks
Here is the custom useInterval hook that I used.
const intervalRef = useRef(null);
const savedCallback = useRef(callback);
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
const tick = () => savedCallback.current();
if (typeof delay === 'number') {
intervalRef.current = window.setInterval(tick, delay);
return () => window.clearInterval(intervalRef.current);
}
}, [delay]);
return intervalRef;
}```

rxjs countdown that triggers method

I am trying to make a 5 mins countdown that triggers a service method and reloads the 5 mins countdown (basically I am trying to reload some data every 5 mins)
constructor(
private reloadDataService: ReloadDataService,
private userService: UserService
) {
this.timer$ = timer(0, 1000).pipe(
scan(acc => --acc, 300),
takeWhile(x => x >= 0),
);
}
realod method is trigger by a button or every 5 mins
reload() {
this.lastRefresh = new Date();
this.reloadDataService.reload()
}
ngOnInit() {
this.getUserDetails();
}
I have tried with
this.timer$ = timer(0, 1000).pipe(
switchMap(() => this.reload()),
scan(acc => --acc, 300),
takeWhile(x => x >= 0),
);
but didn't work - how can I trigger the reload method every 5 mins?
One way is by using interval or timer function offered by rxjs.
Here is an example that I created.
countDown: Subscription = null;
minutes: number = 5;
counter: number = this.minutes * 60;
triggered: number = 0;
start timer function
startTimer(): void {
this.countDown ? this.stopTimer() : null;
this.countDown = interval(1000).subscribe(() => {
--this.counter;
if (!this.counter) {
this.trigger();
}
});
}
stop timer function
stopTimer(): void {
if (this.countDown) {
this.countDown.unsubscribe();
this.countDown = null;
}
}
trigger function that get executed when countdown finish
trigger(): void {
this.counter = this.minutes * 60;
this.stopTimer(); // unsubscribe timer
this.startTimer(); // re subscribe timer
this.triggered++;
// your code
}
codesandbox ui example
I hope this helps you, let me know if you build another solution.
Best wishes,
Dev.klodian
use the subscribe property of timer,
const source = timer(0, 300000);
source.subscribe((_) => this.reload());
Try below code. It will setup the the interval method and when subscribing to refreshInterval$ you can call reload method or any operation that you want to repeat.
const refreshInterval$: Observable<any> = timer(0, 300000)
.pipe(
// Boolean to kill the request if the user closes the component
takeWhile(() => this.killTrigger));
refreshInterval$.subscribe(() => {
// Your code here
});

Discord.JS Command Issue

I've been working on this command (that I have a problem with) where when the user says u?hi, the bot replies before putting you in a set. You are then put in a timeout for 20 seconds, and while you are in the timeout, if you type u?hi, the bot replies gotta wait x seconds. When the timeout ends, they can type u?hi and the cycle keeps going.
However, I've encountered a problem. In my code, after doing u?hi, I get put in a timeout (just like how I planned). However, while in the timeout, if I type u?hi while lets say 1 seconds into the timeout, instead of the bot saying gotta wait 19 more seconds, the bot says gotta wait 19 more seconds and then starts counting down all the way to 0. Here's what I mean (Screenshot):
Here's my code:
const intervalSet = new Set();
bot.on("message", msg => {
let args = msg.content.substring(prefix.length).split(" ");
switch (args[0]) {
case "hi":
var interval = 20;
var intervalID;
if (intervalSet.has(msg.author.id)) {
intervalID = setInterval(() => {
interval -= 1;
if (interval !== 0 && args[0] === 'hi') {
msg.channel.send(`gotta wait ${interval} more seconds`);
}
if (interval === 0) {
clearInterval(intervalID);
msg.channel.send(`Ended`);
intervalSet.delete(msg.author.id);
}
}, 1000);
} else {
intervalSet.add(msg.author.id);
msg.channel.send("heyy");
}
}
});
I've tried moving the
if (interval !== 0 && args[0] === 'hi') {
msg.channel.send(`gotta wait ${interval} more seconds`);
}
part to other places of the code and changing it up but nothing seems to work. What can I do about this?
Yes that's normal with your code. What you need to do is to create a map, named cooldown. User IDs will be linked with times, so you'll be able to calculate for how long the user is in cooldown.
Here is an update of your code:
const cooldown = new Map();
bot.on("message", msg => {
let args = msg.content.substring(prefix.length).split(" ");
switch (args[0]) {
case "hi":
var interval = 20000; // use milliseconds instead of seconds
var intervalID;
if (cooldown.has(msg.author.id)) {
let cooldownTime = Date.now() - cooldown.get(msg.author.id);
let timeToWait = (interval-cooldownTime)/1000;
if(cooldownTime < interval) {
return message.channel.send(`gotta wait ${timeToWait} more seconds`);
}
}
cooldown.set(msg.author.id, Date.now());
msg.channel.send("heyy");
}
});
If you have any questions, don't hesitate to post a comment!

What am I doing bad with localStorage?

I am doing a time-to-click score table but first I have to localstorage each time I get in a game but I dont know how I have been trying everything but it still not working, I need to finish this fast, and I need help... otherwise I would try everyday to resolve this alone because I know that's the way to learn.. When I press the finished button It says that times.push() is not a function.
let times = Array.from(
{ length: 3 }
)
let interval2;
// Timer CountUp
const timerCountUp = () => {
let times = 0;
let current = times;
interval2 = setInterval(() => {
times = current++
saveTimes(times)
return times
},1000);
}
// Saves the times to localStorage
const saveTimes = (times) => {
localStorage.setItem('times', JSON.stringify(times))
}
// Read existing notes from localStorage
const getSavedNotes = () => {
const timesJSON = localStorage.getItem('times')
try {
return timesJSON ? JSON.parse(timesJSON) : []
} catch (e) {
return []
}
}
//Button which starts the countUp
start.addEventListener('click', () => {
timerCountUp();
})
// Button which stops the countUp
document.querySelector('#start_button').addEventListener('click', (e) => {
console.log('click');
times = getSavedNotes()
times.push({
score: interval2
})
if (interval) {
clearInterval(interval);
clearInterval(interval2);
}
})
You probably need to change the line times = JSON.parse(localStorage.times || []) to times = JSON.parse(localStorage.times) || [] this makes sure that if the parsing fails it will still be an array.
Even better is wrap them with try-catch just in case if your JSON string is corrupted and check if the time is an array in the finally if not set it to empty array.

Timer: Play very few Minutes a warnsignal for a duration

I want to build a "timer". User can define a duration and the interval. So it will start with a warnsignat, then there will be a warnsignal, which peeps every interval and at the end there should be one.
The problem is: it doesn't work.
The audio just plays all the time.
Possible errorsources:
peep.loop = false does not work
it does not block.
const peepUrl = require('./../../../Assets/peep.mp3');
const peep = new Audio(peepUrl);
peep.loop = false;
_peep = () => {
peep.play();
if(this.state.myInterval > 0) {
setTimeout(() => {
peep.play();
}, 60000*this.state.myInterval);
}
clearInterval(this.state.myDuration)
peep.play();
}

Categories

Resources