Skip to content

Commit

Permalink
release v1.0.3: background timer use custom native module
Browse files Browse the repository at this point in the history
  • Loading branch information
phidn committed Jan 21, 2023
1 parent 9373de2 commit 0b80eea
Show file tree
Hide file tree
Showing 12 changed files with 597 additions and 488 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,4 @@ v3NoLabelContainer: {
- https://github.com/Vetrivel-VP/react-native-musicplayer
- https://github.com/dr0id007/forest-native
- https://www.npmjs.com/package/react-native-bundle-visualizer
- https://github.com/juanamd/react-native-background-timer-android
1 change: 1 addition & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package="com.phidang.mindfulcheckin">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.android.vending.BILLING"/>
<uses-permission android:name="com.google.android.gms.permission.AD_ID"/>

Expand Down
705 changes: 352 additions & 353 deletions android/app/src/main/assets/index.android.bundle

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package com.phidang.mindfulcheckin;

import android.content.Context;
import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;

import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import java.lang.Runnable;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class BackgroundTimerAndroidModule extends ReactContextBaseJavaModule {
private static final String TAG = "RNBackgroundTimerAndroid";
private static final String TIMER_EVENT = "RNBackgroundTimerAndroid.timer";

private Map<Integer, TimerData> timerDataMap = new HashMap<>();
private Handler handler;

public BackgroundTimerAndroidModule(ReactApplicationContext reactContext) {
super(reactContext);
}

@Override
public String getName() {
return TAG;
}

@ReactMethod
public void setTimer(final int id, final double millis, final boolean repeats, Promise promise) {
try {
setTimer(id, (long) millis, repeats);
promise.resolve(null);
Log.d(TAG, "setTimer for id: " + String.valueOf(id) + " for " + String.valueOf(millis) + " ms. Repeats: " + String.valueOf(repeats));
} catch (Exception e) {
promise.reject(e);
}
}

private void setTimer(final int id, final long millis, final boolean repeats) {
if (handler == null) handler = new Handler();
Runnable runnable = repeats ? getIntervalRunnable(id, millis) : getTimeoutRunnable(id);
handler.postDelayed(runnable, millis);

PowerManager powerManager = (PowerManager) getReactApplicationContext().getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
if (repeats) wakeLock.acquire();
else wakeLock.acquire(millis);

TimerData timerData = new TimerData(id, runnable, wakeLock);
timerDataMap.put(id, timerData);
}

private Runnable getTimeoutRunnable(final int id) {
return new Runnable() {
@Override
public void run() {
timerDataMap.remove(id);
sendTimerEventToJS(id);
}
};
}

private Runnable getIntervalRunnable(final int id, final long millis) {
return new Runnable() {
@Override
public void run() {
sendTimerEventToJS(id);
handler.postDelayed(this, millis);
}
};
}

private void sendTimerEventToJS(final int id) {
if (getReactApplicationContext().hasActiveCatalystInstance()) {
getReactApplicationContext()
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(TIMER_EVENT, id);
Log.d(TAG, "send timer event for id: " + String.valueOf(id));
} else {
Log.d(TAG, "could not send event as there is no active react instance. Event id: " + String.valueOf(id));
}
}

@ReactMethod
public void clearTimer(final int id, final Promise promise) {
try {
clearTimer(id);
promise.resolve(null);
Log.d(TAG, "clearTimer for id: " + String.valueOf(id));
} catch (Exception e) {
promise.reject(e);
}
}

private void clearTimer(final int id) {
TimerData timerData = timerDataMap.get(id);
if (timerData != null) {
if (timerData.wakeLock.isHeld()) timerData.wakeLock.release();
handler.removeCallbacks(timerData.runnable);
timerDataMap.remove(id);
}
}

@Override
public void onCatalystInstanceDestroy() {
super.onCatalystInstanceDestroy();
for (TimerData timerData : timerDataMap.values()) {
if (timerData == null) continue;
try {
if (timerData.wakeLock.isHeld()) timerData.wakeLock.release();
} catch (Exception e) {
Log.e(TAG, "Could not release wakeLock of id: " + timerData.id, e);
}
}
}

@Override
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>();
constants.put("TIMER_EVENT", TIMER_EVENT);
return constants;
}

@ReactMethod
public void addListener(String eventName) {
// Keep: Required for RN built in Event Emitter Calls.
}

@ReactMethod
public void removeListeners(Integer count) {
// Keep: Required for RN built in Event Emitter Calls.
}

private class TimerData {
public int id;
public Runnable runnable;
public WakeLock wakeLock;

public TimerData(int id, Runnable runnable, WakeLock wakeLock) {
this.id = id;
this.runnable = runnable;
this.wakeLock = wakeLock;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.phidang.mindfulcheckin;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.bridge.JavaScriptModule;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class BackgroundTimerAndroidPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(new BackgroundTimerAndroidModule(reactContext));
}

// Deprecated from RN 0.47
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ protected List<ReactPackage> getPackages() {
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new BackgroundTimerAndroidPackage());
return packages;
}

Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mindful-checkin",
"version": "1.0.2",
"version": "1.0.3",
"private": true,
"scripts": {
"prod": "yarn prod-code && yarn clean && yarn bundle && yarn prod-build && yarn prod-folder",
Expand Down Expand Up @@ -53,7 +53,6 @@
"react": "18.1.0",
"react-i18next": "^12.1.1",
"react-native": "0.70.6",
"react-native-background-timer": "^2.4.1",
"react-native-bootsplash": "^4.4.0",
"react-native-calendars": "^1.1292.0",
"react-native-countdown-circle-timer": "^3.1.0",
Expand Down
22 changes: 0 additions & 22 deletions patches/react-native-background-timer+2.4.1.patch

This file was deleted.

11 changes: 3 additions & 8 deletions src/screens/AdminScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { useStore } from '@/store/useStore'
import PageContainer from '@/components/Containers/PageContainer'
import { getAsset } from '@/utilities/assetsHelper'
import useSound from '@/hooks/useSound'
import _BackgroundTimer from 'react-native-background-timer'
import { Platform, StyleSheet, View } from 'react-native'
import notifee from '@notifee/react-native'
import { getYearsDates } from '@/utilities/chartHelper'
import { getRandomIntInclusive, roundNearest } from '@/utilities/commonHelper'
import DeviceInfo from 'react-native-device-info'
import ColorPicker from '@/components/ColorPicker/ColorPicker'
import BackgroundTimer from '@/utilities/BackgroundTimer'

const AdminScreen = () => {
const clearAsyncStorage = () => {
Expand Down Expand Up @@ -86,10 +86,7 @@ const AdminScreen = () => {

const { play } = useSound()
const testBackgroundTimer = () => {
console.log('testBackgroundTimer run')
_BackgroundTimer.runBackgroundTimer(() => {
play(getAsset('bell_10_long'), 1)
}, 1000 * 10)
const intervalId = BackgroundTimer.setInterval(() => console.log('tic'), 500)
}

useEffect(() => {
Expand Down Expand Up @@ -166,9 +163,7 @@ const AdminScreen = () => {
}

const AdminScreen2 = () => {
return (
<View></View>
)
return <View></View>
}

export default AdminScreen
Expand Down
12 changes: 6 additions & 6 deletions src/screens/MeditateScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ const baseNotifeeMTAndroid = {

const MeditateScreen = ({ route, navigation }) => {
const { params } = route
// if (__DEV__) {
// params.duration = 40
// params.interval = 10
// preparationTime = 5
// numberOfInviteBell = 2
// }
if (__DEV__) {
params.duration = 40
params.interval = 10
preparationTime = 5
numberOfInviteBell = 2
}

const msDuration = sToMs(params.duration)
const msInterval = sToMs(params.interval)
Expand Down
Loading

0 comments on commit 0b80eea

Please sign in to comment.