Skip to content

Commit 17bfbcc

Browse files
authored
Merge pull request #1 from nilavanraj/CustomNotification
Complete Custom notification
2 parents 6969ae2 + 293651a commit 17bfbcc

16 files changed

+12952
-23468
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.reactnativecustomtimernotification
2+
3+
class CNException {
4+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.reactnativecustomtimernotification
2+
3+
object Constants {
4+
object NOTIFICATION {
5+
const val BODY = "body"
6+
const val TITLE = "title"
7+
const val PAYLOAD = "payload"
8+
const val ID = "id"
9+
const val IS_COUNT = "isCount"
10+
const val IMAGEVIEW = "ImageView"
11+
const val VIEW = "View"
12+
const val ZEROTIME = "ZeroTime"
13+
14+
}
15+
object PADDING {
16+
const val TOP = "PaddingTop"
17+
const val LEFT = "PaddingLeft"
18+
const val RIGHT = "PaddingRight"
19+
const val BOTTOM = "PaddingBottom"
20+
21+
}
22+
object VIEW {
23+
const val SIZE = "size"
24+
const val TYPE = "type"
25+
const val HIDE = "hide"
26+
const val BOLD = "bold"
27+
28+
29+
}
30+
31+
}
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
package com.reactnativecustomtimernotification
2+
3+
import android.app.*
4+
import android.content.Intent
5+
import android.graphics.BitmapFactory
6+
import android.graphics.Color
7+
import android.graphics.Typeface
8+
import android.icu.text.SimpleDateFormat
9+
import android.icu.util.Calendar
10+
import android.os.Build
11+
import android.os.Handler
12+
import android.os.SystemClock
13+
import android.text.SpannableString
14+
import android.text.style.StyleSpan
15+
import android.util.Base64
16+
import android.util.Log
17+
import android.util.TypedValue
18+
import android.view.View
19+
import android.widget.RemoteViews
20+
import androidx.core.app.NotificationCompat
21+
import com.facebook.react.bridge.Callback
22+
import com.facebook.react.bridge.ReactApplicationContext
23+
import com.facebook.react.bridge.ReactContextBaseJavaModule
24+
import com.facebook.react.bridge.ReactMethod
25+
import com.facebook.react.bridge.ReadableMap
26+
import java.util.*
27+
28+
29+
class CustomNotificationModule: ReactContextBaseJavaModule {
30+
var loading : Boolean = false;
31+
lateinit var notificationManager: NotificationManager
32+
lateinit var builder: Notification.Builder
33+
val channelId:String = "255"
34+
var packageName: String = ""
35+
var myContext: ReactApplicationContext;
36+
val imageLayouts = arrayOf(R.layout.image_view_layout1, R.layout.image_view_layout);
37+
val imageViews = arrayOf(R.id.imageView2, R.id.imageView1);
38+
var imageCount = 0 ;
39+
lateinit var notificationBuilder:NotificationCompat.Builder;
40+
41+
constructor (context:ReactApplicationContext):super(context){
42+
this.loading= true;
43+
this.myContext= context
44+
this.packageName=this.myContext.getPackageName()
45+
}
46+
47+
override fun getName(): String {
48+
return "CustomNotificationModule"
49+
}
50+
51+
@ReactMethod
52+
fun CustomNotification(objectData:ReadableMap,callback: Callback) {
53+
try{
54+
val payload = objectData.getString(Constants.NOTIFICATION.PAYLOAD);
55+
val title = objectData.getString(Constants.NOTIFICATION.TITLE);
56+
val body = objectData.getString(Constants.NOTIFICATION.BODY);
57+
val id = objectData.getInt(Constants.NOTIFICATION.ID);
58+
59+
val intent = Intent(myContext, NotificationEventReceiver::class.java)
60+
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
61+
intent.putExtra("id",id);
62+
intent.putExtra("action","press");
63+
intent.putExtra("payload",payload);
64+
val pendingIntent = PendingIntent.getBroadcast(myContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
65+
66+
val onCancelIntent = Intent(myContext, OnClickBroadcastReceiver::class.java)
67+
onCancelIntent.putExtra("id",id);
68+
onCancelIntent.putExtra("action","cancel");
69+
onCancelIntent.putExtra("payload",payload);
70+
val onDismissPendingIntent =
71+
PendingIntent.getBroadcast(myContext, 0, onCancelIntent, 0)
72+
73+
val notificationLayout = RemoteViews(packageName, R.layout.notification_collapsed);
74+
75+
// View Array
76+
val View = objectData.getArray(Constants.NOTIFICATION.VIEW);
77+
for (i in 0..(View?.size()?.minus(1) ?: 0)) {
78+
val item = View?.getMap(i);
79+
if(item!=null && item.hasKey(Constants.VIEW.TYPE) && item.getInt(Constants.VIEW.TYPE)==1){
80+
setImageView(item, notificationLayout,imageCount);
81+
imageCount+=1;
82+
}
83+
else if(item!=null && item.hasKey(Constants.VIEW.TYPE) && item.getInt(Constants.VIEW.TYPE)==2){
84+
setTextView(item,notificationLayout);
85+
}
86+
else if(item!=null && item.hasKey(Constants.VIEW.TYPE) && item.getInt(Constants.VIEW.TYPE)==3) {
87+
setChronometer(id,item, notificationLayout);
88+
}
89+
90+
// textView.setString(R.id.imageView1, "layout_width", "34dp");
91+
// textView.setViewPadding (Align.CENTER)
92+
}
93+
94+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
95+
val notificationChannel = NotificationChannel(channelId,"Lineup",NotificationManager.IMPORTANCE_HIGH)
96+
notificationChannel.setDescription("Lineup out")
97+
notificationChannel.enableLights(true)
98+
notificationChannel.setLightColor(Color.RED)
99+
notificationManager = myContext.getSystemService(NotificationManager::class.java)
100+
notificationManager.createNotificationChannel(notificationChannel)
101+
102+
103+
} else {
104+
notificationManager = myContext.getSystemService(NotificationManager::class.java)
105+
}
106+
notificationBuilder =
107+
NotificationCompat.Builder(myContext,channelId)
108+
notificationBuilder.setAutoCancel(true)
109+
.setWhen(System.currentTimeMillis())
110+
.setSmallIcon(myContext.getResources().getIdentifier("ic_launcher", "mipmap", myContext.getPackageName()))
111+
.setContentTitle(title)
112+
.setContentText(body)
113+
.setOnlyAlertOnce(true)
114+
.setCustomContentView(notificationLayout)
115+
.setContentIntent(pendingIntent)
116+
.setDeleteIntent(onDismissPendingIntent)
117+
.setPriority(NotificationCompat.PRIORITY_HIGH);
118+
notificationManager.notify(id,notificationBuilder.build());
119+
120+
} catch (e:Exception) {
121+
callback.invoke(e.toString());
122+
Log.e("Notification crash",e.toString())
123+
// throw RuntimeException("Notification crash",e)
124+
}
125+
}
126+
private fun setPadding(item:ReadableMap?, View:RemoteViews,path:Int){
127+
var paddingLeft: Int = 0;
128+
var paddingTop: Int = 0;
129+
var paddingBottom: Int = 0;
130+
var paddingRight: Int = 0;
131+
132+
133+
if(item!=null&&item.hasKey(Constants.PADDING.TOP))
134+
paddingTop = item.getInt(Constants.PADDING.TOP);
135+
if(item!=null&&item.hasKey(Constants.PADDING.LEFT))
136+
paddingLeft = item.getInt(Constants.PADDING.LEFT);
137+
if(item!=null&&item.hasKey(Constants.PADDING.RIGHT))
138+
paddingRight = item.getInt(Constants.PADDING.RIGHT);
139+
if(item!=null&&item.hasKey(Constants.PADDING.BOTTOM))
140+
paddingBottom = item.getInt(Constants.PADDING.BOTTOM);
141+
View.setViewPadding(
142+
path,
143+
paddingLeft ?: 0,
144+
paddingTop ?: 0,
145+
paddingRight ?: 0,
146+
paddingBottom ?: 0
147+
);
148+
}
149+
private fun setTextView(item:ReadableMap?, notificationLayout:RemoteViews){
150+
val textView = RemoteViews(myContext.getPackageName(), R.layout.text_view_layout)
151+
var bold = 0;
152+
if(item!=null && item.hasKey(Constants.VIEW.BOLD)){
153+
bold = item.getInt(Constants.VIEW.BOLD)
154+
}
155+
val s = SpannableString(item?.getString("name"))
156+
s.setSpan(StyleSpan(bold), 0, s.length, 0)
157+
textView.setTextViewText(R.id.textView1, s)
158+
159+
val float:Float=item?.getDouble(Constants.VIEW.SIZE)?.toFloat()!!
160+
textView.setTextViewTextSize(R.id.textView1, TypedValue.COMPLEX_UNIT_SP, float);
161+
textView.setTextColor(R.id.textView1,Color.parseColor(item?.getString("color")));
162+
if(item?.getBoolean("setViewVisibility"))
163+
textView.setViewVisibility (R.id.textView1,
164+
View.INVISIBLE)
165+
setPadding(item,textView,R.id.textView1);
166+
notificationLayout.addView(R.id.main, textView)
167+
}
168+
private fun setImageView(item:ReadableMap?, notificationLayout:RemoteViews,i:Int){
169+
val remoteLocalImage =
170+
RemoteViews(myContext.getPackageName(), imageLayouts[i]);
171+
val url: String? = item?.getString("uri");
172+
val decodedString: ByteArray = Base64.decode(url, Base64.DEFAULT)
173+
val decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.size)
174+
notificationLayout.addView(R.id.main, remoteLocalImage);
175+
notificationLayout.setImageViewBitmap(imageViews[i], decodedByte);
176+
setPadding(item, remoteLocalImage,imageViews[i]);
177+
}
178+
private fun setChronometer(id:Int, item:ReadableMap?, notificationLayout:RemoteViews){
179+
if(item!=null) {
180+
val datetime = item.getString(Constants.NOTIFICATION.ZEROTIME);
181+
val remoteLocalChronometer =
182+
RemoteViews(myContext.getPackageName(), R.layout.chronometer_view_layout);
183+
notificationLayout.addView(R.id.main, remoteLocalChronometer)
184+
val float:Float=item?.getDouble(Constants.VIEW.SIZE)?.toFloat()!!
185+
remoteLocalChronometer.setTextViewTextSize(R.id.timerCustom, TypedValue.COMPLEX_UNIT_SP, float);
186+
remoteLocalChronometer.setTextColor(R.id.timerCustom,Color.parseColor(item?.getString("color")));
187+
val sdf = SimpleDateFormat("dd-MM-yyyy HH:mm:ss", Locale.ENGLISH)
188+
189+
val startTime = SystemClock.elapsedRealtime()
190+
val endTime: Calendar = Calendar.getInstance()
191+
endTime.time = sdf.parse(datetime)
192+
193+
val now = Date()
194+
val elapsed: Long = now.getTime() - endTime.timeInMillis
195+
val remainingTime = startTime - elapsed
196+
197+
notificationLayout.setChronometerCountDown(R.id.timerCustom, true);
198+
notificationLayout.setChronometer(
199+
R.id.timerCustom,
200+
remainingTime,
201+
("%tM:%tS"),
202+
true
203+
);
204+
setPadding(item, remoteLocalChronometer, R.id.timerCustom);
205+
val handler = Handler()
206+
207+
handler.postDelayed({
208+
notificationLayout.setChronometerCountDown(R.id.timerCustom, true);
209+
notificationLayout.setChronometer(R.id.timerCustom, remainingTime, ("%tM:%tS"), false);
210+
if(item.getBoolean(Constants.VIEW.HIDE))
211+
notificationLayout.setViewVisibility (R.id.timerCustom, View.INVISIBLE)
212+
notificationBuilder.setCustomContentView(notificationLayout)
213+
notificationManager.notify(id,notificationBuilder.build())
214+
}, Math.abs(elapsed))
215+
}
216+
}
217+
}
218+
219+

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@ import com.facebook.react.uimanager.ViewManager
77

88

99
class CustomTimerNotificationPackage : ReactPackage {
10-
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
11-
return listOf(CustomTimerNotificationModule(reactContext))
12-
}
10+
override fun createNativeModules(
11+
reactContext: ReactApplicationContext): List<NativeModule> {
12+
val modules = ArrayList<NativeModule>()
13+
14+
modules.add(CustomNotificationModule(reactContext))
15+
modules.add(CustomTimerNotificationModule(reactContext))
16+
return modules
17+
}
1318

1419
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
1520
return emptyList()
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:orientation="vertical"
4+
android:layout_width="match_parent"
5+
android:layout_height="match_parent">
6+
<Chronometer
7+
android:id="@+id/timerCustom"
8+
style="@style/TextAppearance.Compat.Notification.Title"
9+
android:layout_weight="5"
10+
android:layout_width="wrap_content"
11+
android:layout_height="match_parent"
12+
android:gravity="right|center_vertical"
13+
android:maxLines="1"
14+
android:text="timerCustom"
15+
android:textSize="20dp" />
16+
17+
</LinearLayout>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout
3+
xmlns:android="http://schemas.android.com/apk/res/android"
4+
android:layout_width="match_parent"
5+
android:layout_height="match_parent"
6+
android:id="@+id/ImageView"
7+
>
8+
9+
<ImageView
10+
xmlns:android="http://schemas.android.com/apk/res/android"
11+
android:id="@+id/imageView1"
12+
android:layout_width="match_parent"
13+
android:layout_height="match_parent"
14+
15+
/>
16+
17+
</LinearLayout>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout
3+
xmlns:android="http://schemas.android.com/apk/res/android"
4+
android:layout_width="match_parent"
5+
android:layout_height="match_parent"
6+
android:id="@+id/ImageView1"
7+
>
8+
9+
<ImageView
10+
xmlns:android="http://schemas.android.com/apk/res/android"
11+
android:id="@+id/imageView2"
12+
android:layout_width="match_parent"
13+
android:layout_height="match_parent"
14+
15+
/>
16+
17+
</LinearLayout>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:layout_width="match_parent"
4+
android:layout_height="120dp"
5+
6+
android:orientation="vertical"
7+
android:id="@+id/main"
8+
>
9+
10+
</RelativeLayout>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout
3+
xmlns:android="http://schemas.android.com/apk/res/android"
4+
android:layout_width="match_parent"
5+
android:layout_height="match_parent"
6+
android:id="@+id/LinearLayout"
7+
>
8+
<TextView
9+
android:id="@+id/textView1"
10+
android:layout_width="wrap_content"
11+
android:layout_height="wrap_content"
12+
android:text="TextView"
13+
android:textAppearance="?android:attr/textAppearanceLarge" />
14+
</LinearLayout>
15+

example/android/build.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@ buildscript {
55
minSdkVersion = 16
66
compileSdkVersion = 29
77
targetSdkVersion = 29
8+
9+
ndkVersion = "21.4.7075529"
810
}
911
repositories {
1012
google()
1113
mavenCentral()
1214
jcenter()
1315
}
1416
dependencies {
15-
classpath("com.android.tools.build:gradle:3.5.3")
17+
classpath 'com.android.tools.build:gradle:4.0.0'
1618

1719
// NOTE: Do not place your application dependencies here; they belong
1820
// in the individual module build.gradle files

0 commit comments

Comments
 (0)