Skip to content

Commit 8b7716e

Browse files
committed
performance improvement and bug fix
1 parent 77162ec commit 8b7716e

File tree

7 files changed

+169
-125
lines changed

7 files changed

+169
-125
lines changed

README.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ AndroidManifest
2626
```title``` Title of the notification <br>
2727
```body``` Body of the notification <br>
2828
```id``` unique number <br>
29-
```sec``` Time in seconds <br>
30-
29+
```date``` Time at which zero comes <br>
3130
```js
3231
import { TimerNotification, onEvent } from "react-native-custom-timer-notification";
3332

@@ -37,15 +36,15 @@ onEvent(event=>{
3736
console.log(event)
3837
});
3938

40-
TimerNotification({
41-
payload: JSON.stringify("notificationOpen?.data"),
42-
title: "My notification",
43-
body:"Much longer text that cannot fit one line... ",
44-
id: 1,
45-
sec:60,
46-
remove:false, // optional
47-
foreground:false,
48-
})
39+
TimerNotification({
40+
payload: JSON.stringify('notificationOpen?.data'),
41+
title: 'My notification',
42+
body: 'Much longer text that cannot fit one line... ',
43+
id: 160211114,
44+
remove: false, // optional
45+
foreground: false,
46+
date: new Date(Date.now() + 20000),
47+
});
4948
```
5049

5150
## Contributing

android/src/main/java/com/reactnativecustomtimernotification/CustomTimerNotificationModule.kt

Lines changed: 59 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,32 @@ import android.content.BroadcastReceiver
99
import android.content.Context
1010
import android.content.Intent
1111
import android.content.IntentFilter
12-
import android.content.pm.PackageManager
1312
import android.graphics.Color
13+
import android.icu.text.SimpleDateFormat
14+
import android.icu.util.Calendar
1415
import android.os.Build
1516
import android.os.CountDownTimer
17+
import android.os.Handler
18+
import android.os.SystemClock
1619
import android.util.Log
1720
import android.view.View
1821
import android.widget.RemoteViews
1922
import androidx.core.app.NotificationCompat
20-
import com.facebook.react.bridge.Callback
23+
import com.facebook.react.bridge.Arguments
2124
import com.facebook.react.bridge.ReactApplicationContext
2225
import com.facebook.react.bridge.ReactContextBaseJavaModule
2326
import com.facebook.react.bridge.ReactMethod
2427
import com.facebook.react.bridge.ReadableMap
28+
import com.facebook.react.bridge.WritableMap
2529
import com.facebook.react.modules.core.DeviceEventManagerModule
26-
import org.json.JSONObject
27-
import com.facebook.react.bridge.WritableMap;
28-
import com.facebook.react.bridge.Arguments;
30+
import java.util.*
31+
import kotlin.time.milliseconds
2932

3033

3134
class CustomTimerNotificationModule: ReactContextBaseJavaModule {
3235
var loading : Boolean = false;
33-
var firstForegound : Boolean = true;
34-
var ifCancel = false;
36+
var foregound : Boolean = false;
37+
3538
lateinit var notificationManager: NotificationManager
3639
lateinit var builder: Notification.Builder
3740
val channelId:String = "255"
@@ -47,13 +50,13 @@ class CustomTimerNotificationModule: ReactContextBaseJavaModule {
4750
myContext.registerReceiver(object : BroadcastReceiver() {
4851
override fun onReceive(context: Context, intent: Intent) {
4952
try {
50-
51-
ifCancel = true
5253
val extras = intent.extras
5354
val params: WritableMap = Arguments.createMap()
5455
params.putInt("id", extras!!.getInt("id"))
5556
params.putString("action", extras!!.getString("action"))
5657
params.putString("payload", extras!!.getString("payload"))
58+
removeNotification(extras!!.getInt("id"),foregound)
59+
5760
sendEvent("notificationClick", params)
5861
} catch (e: Exception) {
5962
println(e)
@@ -87,6 +90,17 @@ class CustomTimerNotificationModule: ReactContextBaseJavaModule {
8790
val payload = objectData.getString("payload");
8891
val id =objectData.getInt("id");
8992

93+
val datetime = objectData.getString("date")
94+
val sdf = SimpleDateFormat("dd-MM-yyyy HH:mm:ss", Locale.ENGLISH)
95+
96+
val startTime = SystemClock.elapsedRealtime()
97+
val endTime: Calendar = Calendar.getInstance()
98+
endTime.time = sdf.parse(datetime)
99+
100+
val now = Date()
101+
val elapsed: Long = now.getTime() - endTime.timeInMillis
102+
val remainingTime = startTime - elapsed
103+
90104
val intent = Intent(myContext, NotificationEventReceiver::class.java)
91105
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
92106
intent.putExtra("id",id);
@@ -104,17 +118,16 @@ class CustomTimerNotificationModule: ReactContextBaseJavaModule {
104118
val notificationLayout = RemoteViews(packageName, R.layout.notification_open);
105119
notificationLayout.setTextViewText(R.id.title,title)
106120
notificationLayout.setTextViewText(R.id.text,body)
107-
notificationLayout.setTextViewText(R.id.timer,remainingTime)
121+
122+
// notificationLayout.setTextViewText(R.id.timer,remainingTime)
123+
notificationLayout.setChronometerCountDown(R.id.simpleChronometer, true);
124+
notificationLayout.setChronometer(R.id.simpleChronometer, remainingTime, ("%sM:%sS"), true);
125+
108126

109127
// try {
110128
// notificationLayout.setTextColor(R.id.timer , Color.parseColor(objectData.getString("timeColor")));
111129
// } catch (e:Exception){}
112130

113-
if(visbleTimer){
114-
notificationLayout.setViewVisibility (R.id.timer,
115-
View.INVISIBLE)
116-
}
117-
118131
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
119132
val notificationChannel =
120133
NotificationChannel(channelId, "Timer", NotificationManager.IMPORTANCE_HIGH)
@@ -127,7 +140,6 @@ class CustomTimerNotificationModule: ReactContextBaseJavaModule {
127140
val notificationBuilder:NotificationCompat.Builder =
128141
NotificationCompat.Builder(myContext,channelId)
129142
notificationBuilder.setAutoCancel(true)
130-
.setWhen(System.currentTimeMillis())
131143
.setSmallIcon(myContext.getResources().getIdentifier("ic_launcher", "mipmap", myContext.getPackageName()))
132144
.setContentTitle(title)
133145
.setContentText(body)
@@ -137,70 +149,54 @@ class CustomTimerNotificationModule: ReactContextBaseJavaModule {
137149
.setContentIntent(pendingIntent)
138150
.setDeleteIntent(onDismissPendingIntent)
139151
.setPriority(NotificationCompat.PRIORITY_HIGH)
140-
return notificationBuilder
152+
.setWhen(endTime.getTimeInMillis());
153+
val handler = Handler()
154+
handler.postDelayed({
155+
notificationLayout.setChronometer(R.id.simpleChronometer, remainingTime, ("%sM:%sS"), false);
156+
try {
157+
val remove =objectData.getBoolean("remove");
158+
val foreground =objectData.getBoolean("foreground");
159+
if(remove){
160+
removeNotification(id,foreground)
161+
} else {
162+
notificationLayout.setViewVisibility (R.id.simpleChronometer,
163+
View.INVISIBLE)
164+
}
165+
} catch (e:Exception){}
141166

167+
notificationBuilder.setCustomContentView(notificationLayout)
168+
notificationManager.notify(id,notificationBuilder.build())
169+
}, Math.abs(elapsed))
170+
return notificationBuilder
142171
}
172+
143173
fun updatePop(objectData:ReadableMap,remainingTime:String,visbleTimer:Boolean){
144174
val id =objectData.getInt("id");
145175
val notificationBuilder:NotificationCompat.Builder = notificationPop(objectData,remainingTime,visbleTimer)
146176
notificationManager.notify(id,notificationBuilder.build())
147177
}
148178
fun removeNotification (id:Int,foreground:Boolean) {
149-
150179
val notificationManager = myContext.getSystemService(NotificationManager::class.java)
151180
if(foreground)
152181
ForegroundService.stopService(myContext)
153182
else
154183
notificationManager.cancel( id ) ;
155184
}
156-
fun countdown(objectData:ReadableMap,sec:Int) {
157-
val secLong = sec.toLong()*1000;
158-
val id =objectData.getInt("id");
159-
val foreground =objectData.getBoolean("foreground");
160-
161-
object : CountDownTimer(secLong, 1000) {
162-
override fun onTick(millisUntilFinished: Long) {
163-
val remainingSec:Int = (millisUntilFinished / 1000).toInt()
164-
val min = convert((remainingSec/60).toInt().toString())
165-
val secInMin = convert((remainingSec%60).toInt().toString())
166-
val remainingTime:String = "$min : $secInMin"
167-
if(ifCancel){
168-
cancel();
169-
if(foreground){
170-
ForegroundService.stopService(myContext)
171-
}
172-
}
173-
else{
174-
if(foreground&&firstForegound){
175-
firstForegound=false
176-
ForegroundService.startService(myContext,objectData,remainingTime)
177-
} else
178-
updatePop(objectData,remainingTime,false)
185+
@ReactMethod
186+
fun TimerNotification(objectData:ReadableMap) {
179187

180-
}
181-
}
188+
val remainingSec:Int = (10000 / 1000).toInt()
189+
val min = convert((remainingSec/60).toInt().toString())
190+
val secInMin = convert((remainingSec%60).toInt().toString())
191+
val remainingTime:String = "$min : $secInMin"
182192

183-
override fun onFinish() {
184-
try {
185-
val remove =objectData.getBoolean("remove");
186-
if(remove){
187-
removeNotification(id,foreground)
188-
} else {
189-
println("onFinish")
190-
updatePop(objectData,"",true)
191-
}
192-
} catch (e:Exception){}
193+
val foreground =objectData.getBoolean("foreground");
193194

194-
}
195-
}.start()
196-
}
197-
198-
@ReactMethod
199-
fun TimerNotification(objectData:ReadableMap) {
200-
firstForegound=true;
201-
ifCancel = false;
202-
val sec =objectData.getInt("sec");
203-
countdown(objectData,sec)
195+
if(foreground){
196+
foregound=true;
197+
ForegroundService.startService(myContext,objectData)
198+
} else
199+
updatePop(objectData,remainingTime,false)
204200
//promise.resolve(a * b)
205201

206202
}

android/src/main/java/com/reactnativecustomtimernotification/ForegroundService.kt

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,38 @@ import android.app.PendingIntent
66
import android.app.Service
77
import android.content.Context
88
import android.content.Intent
9-
import android.os.Build
10-
import android.os.IBinder
119
import androidx.core.app.NotificationCompat
1210
import androidx.core.content.ContextCompat
13-
import android.os.CountDownTimer
1411
import android.graphics.Color
1512
import android.app.Notification
13+
import android.icu.text.SimpleDateFormat
14+
import android.icu.util.Calendar
15+
import android.os.*
16+
import android.view.View
1617
import android.widget.RemoteViews;
1718
import com.facebook.react.bridge.ReadableMap;
19+
import java.util.*
1820

1921
class ForegroundService : Service() {
2022
private val CHANNEL_ID = "255"
2123

2224
companion object {
23-
fun startService(context: Context, objectData: ReadableMap,remainingTime:String) {
25+
fun startService(context: Context, objectData: ReadableMap) {
2426
val startIntent = Intent(context, ForegroundService::class.java)
2527

2628
val title = objectData.getString("title");
2729
val body = objectData.getString("body");
2830
val payload = objectData.getString("payload");
2931
val id = objectData.getInt("id");
32+
val datetime = objectData.getString("date")
33+
34+
try {
35+
val remove =objectData.getBoolean("remove");
36+
startIntent.putExtra("remove", remove)
37+
} catch (e:Exception){}
38+
39+
startIntent.putExtra("date", datetime)
3040
startIntent.putExtra("id", id)
31-
startIntent.putExtra("remainingTime", remainingTime)
3241
startIntent.putExtra("title", title)
3342
startIntent.putExtra("body", body)
3443
startIntent.putExtra("payload", payload)
@@ -40,16 +49,12 @@ class ForegroundService : Service() {
4049
context.stopService(stopIntent)
4150
}
4251
}
43-
fun getActiveNotifications (intent: Intent?):Notification{
52+
fun getActiveNotifications (intent: Intent?,displayerTimer:Boolean,remainingTime:Long):Notification{
4453

4554
val title = intent?.getStringExtra("title");
4655
val body = intent?.getStringExtra("body");
4756
val payload = intent?.getStringExtra("payload");
4857
val id:Int? = intent?.getIntExtra("id",0)
49-
println(id)
50-
51-
val remainingTime = intent?.getStringExtra("remainingTime");
52-
5358

5459
val intent = Intent(this, NotificationEventReceiver::class.java)
5560
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
@@ -58,7 +63,6 @@ class ForegroundService : Service() {
5863
intent.putExtra("payload",payload);
5964
val pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
6065

61-
6266
val onCancelIntent = Intent(this, OnClickBroadcastReceiver::class.java)
6367
onCancelIntent.putExtra("id",id);
6468
onCancelIntent.putExtra("action","cancel");
@@ -69,7 +73,13 @@ class ForegroundService : Service() {
6973
val notificationLayout = RemoteViews(packageName, R.layout.notification_open);
7074
notificationLayout.setTextViewText(R.id.title,title)
7175
notificationLayout.setTextViewText(R.id.text,body)
72-
notificationLayout.setTextViewText(R.id.timer,remainingTime)
76+
if(displayerTimer){
77+
notificationLayout.setChronometerCountDown(R.id.simpleChronometer, true);
78+
notificationLayout.setChronometer(R.id.simpleChronometer, remainingTime, ("%tM:%tS"), true);
79+
} else {
80+
notificationLayout.setChronometerCountDown(R.id.simpleChronometer, false);
81+
notificationLayout.setChronometer(R.id.simpleChronometer, remainingTime, ("%tM:%tS"), false);
82+
}
7383

7484
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
7585
val notificationChannel =
@@ -93,12 +103,38 @@ class ForegroundService : Service() {
93103
.setDeleteIntent(onDismissPendingIntent)
94104
.setPriority(NotificationCompat.PRIORITY_HIGH)
95105
.build();
106+
107+
96108
return notification
97109
}
98110
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
99111
val id:Int? = intent?.getIntExtra("id",0)
100112

101-
startForeground(id!!, getActiveNotifications(intent))
113+
val datetime = intent?.getStringExtra("date")
114+
val sdf = SimpleDateFormat("dd-MM-yyyy HH:mm:ss", Locale.ENGLISH)
115+
116+
val startTime = SystemClock.elapsedRealtime()
117+
val endTime: Calendar = Calendar.getInstance()
118+
endTime.time = sdf.parse(datetime)
119+
120+
val now = Date()
121+
val elapsed: Long = now.getTime() - endTime.timeInMillis
122+
val remainingTime = startTime - elapsed
123+
124+
val handler = Handler()
125+
handler.postDelayed({
126+
try {
127+
val remove =intent?.getBooleanExtra("remove",false);
128+
if(remove!!){
129+
stopService(this)
130+
}else{
131+
startForeground(id!!,getActiveNotifications(intent,false,remainingTime))
132+
}
133+
} catch (e:Exception){}
134+
}, Math.abs(elapsed))
135+
136+
137+
startForeground(id!!, getActiveNotifications(intent,true,remainingTime))
102138
return START_NOT_STICKY
103139
}
104140

android/src/main/res/layout/notification_open.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@
3535

3636
</LinearLayout>
3737

38-
<TextView
39-
android:id="@+id/timer"
38+
39+
<Chronometer
40+
android:id="@+id/simpleChronometer"
4041
style="@style/TextAppearance.Compat.Notification.Title"
4142
android:layout_weight="5"
4243

0 commit comments

Comments
 (0)