WIP push notifications likes
This commit is contained in:
parent
0aa7b1001f
commit
16f9d7f90d
@ -1,21 +1,24 @@
|
||||
package com.isolaatti
|
||||
|
||||
import android.app.Application
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import com.google.firebase.Firebase
|
||||
import com.google.firebase.messaging.FirebaseMessaging
|
||||
import com.isolaatti.connectivity.ConnectivityCallbackImpl
|
||||
import com.isolaatti.push_notifications.FcmService
|
||||
import com.isolaatti.push_notifications.PushNotificationsApi
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import retrofit2.awaitResponse
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -27,6 +30,8 @@ class MyApplication : Application() {
|
||||
companion object {
|
||||
lateinit var myApp: MyApplication
|
||||
const val LOG_TAG = "MyApplication"
|
||||
|
||||
const val LIKES_NOTIFICATION_CHANNEL_ID = "like notification"
|
||||
}
|
||||
|
||||
@Inject
|
||||
@ -42,18 +47,27 @@ class MyApplication : Application() {
|
||||
connectivityCallbackImpl = ConnectivityCallbackImpl()
|
||||
getSystemService(ConnectivityManager::class.java).registerDefaultNetworkCallback(connectivityCallbackImpl)
|
||||
|
||||
FirebaseMessaging.getInstance().token.addOnCompleteListener {
|
||||
if(!it.isSuccessful) {
|
||||
Log.w(LOG_TAG, "Failed fetching fcm token")
|
||||
return@addOnCompleteListener
|
||||
}
|
||||
|
||||
FirebaseMessaging.getInstance().token.addOnSuccessListener {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val response = pushNotificationsApi.registerDevice(it.result).awaitResponse()
|
||||
Log.d(FcmService.LOG_TAG, "Device registered. FCM token: $it.result")
|
||||
Log.d(FcmService.LOG_TAG, "Response: isSuccessful: ${response.isSuccessful}")
|
||||
val response = pushNotificationsApi.registerDevice(it.toRequestBody()).awaitResponse()
|
||||
}
|
||||
}
|
||||
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||
createLikesNotificationChannel(notificationManager)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private fun createLikesNotificationChannel(notificationManager: NotificationManager) {
|
||||
val name = getString(R.string.likes_notification_channel)
|
||||
val description = getString(R.string.likes_notification_channel_description)
|
||||
val importance = NotificationManager.IMPORTANCE_DEFAULT
|
||||
val channel = NotificationChannel(LIKES_NOTIFICATION_CHANNEL_ID, name, importance).also {
|
||||
it.description = description
|
||||
}
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
override fun onTerminate() {
|
||||
|
||||
@ -19,4 +19,17 @@ object CoilImageLoader {
|
||||
add(SvgDecoder.Factory())
|
||||
}.build()
|
||||
}
|
||||
|
||||
fun getImageLoader(context: Context): ImageLoader {
|
||||
return ImageLoader
|
||||
.Builder(context)
|
||||
.memoryCache {
|
||||
MemoryCache.Builder(context)
|
||||
.maxSizePercent(0.25)
|
||||
.build()
|
||||
}
|
||||
.components {
|
||||
add(SvgDecoder.Factory())
|
||||
}.build()
|
||||
}
|
||||
}
|
||||
@ -1,22 +1,52 @@
|
||||
package com.isolaatti.push_notifications
|
||||
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
import android.util.Log
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import coil.Coil
|
||||
import coil.request.ImageRequest
|
||||
import com.google.firebase.messaging.FirebaseMessagingService
|
||||
import com.google.firebase.messaging.RemoteMessage
|
||||
import dagger.hilt.EntryPoint
|
||||
import com.isolaatti.MyApplication
|
||||
import com.isolaatti.R
|
||||
import com.isolaatti.common.CoilImageLoader
|
||||
import com.isolaatti.notifications.domain.LikeNotification
|
||||
import com.isolaatti.utils.UrlGen
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.ResponseBody.Companion.toResponseBody
|
||||
import retrofit2.awaitResponse
|
||||
import retrofit2.http.Url
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class FcmService : FirebaseMessagingService() {
|
||||
companion object {
|
||||
const val LOG_TAG = "FcmService"
|
||||
|
||||
object NotificationsConstants {
|
||||
|
||||
const val NOTIFICATION_ID = "id"
|
||||
const val TIMESTAMP = "timeStamp"
|
||||
const val USER_ID = "userId"
|
||||
const val READ = "read"
|
||||
const val RELATED_NOTIFICATIONS = "relatedNotifications"
|
||||
|
||||
object LikeNotificationConstants {
|
||||
const val LIKE_ID = "likeId"
|
||||
const val POST_ID = "postId"
|
||||
const val AUTHOR_ID = "authorId"
|
||||
const val AUTHOR_NAME = "authorName"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Inject
|
||||
@ -25,19 +55,70 @@ class FcmService : FirebaseMessagingService() {
|
||||
override fun onNewToken(token: String) {
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val response = pushNotificationsApi.registerDevice(token).awaitResponse()
|
||||
Log.d(LOG_TAG, "Device registered. FCM token: $token")
|
||||
Log.d(LOG_TAG, "Response: isSuccessful: ${response.isSuccessful}")
|
||||
val response = pushNotificationsApi.registerDevice(token.toRequestBody()).awaitResponse()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onMessageReceived(message: RemoteMessage) {
|
||||
super.onMessageReceived(message)
|
||||
Log.d(LOG_TAG, "onMessageReceived")
|
||||
val type = message.data["type"]
|
||||
|
||||
Log.d(LOG_TAG, "Message received")
|
||||
message.data.forEach { t, u ->
|
||||
Log.d(LOG_TAG, "$t $u")
|
||||
when(type) {
|
||||
LikeNotification.TYPE -> showLikeNotification(message.data)
|
||||
|
||||
else -> {
|
||||
Log.i(LOG_TAG, "Not showing notification of unknown type: ${message.data}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLikeNotification(data: Map<String, String>) {
|
||||
val notificationId = data[NotificationsConstants.NOTIFICATION_ID]?.toIntOrNull()
|
||||
val relatedNotifications = data[NotificationsConstants.RELATED_NOTIFICATIONS]?.trimStart('[')?.trimEnd(']')?.split(",")
|
||||
val likeId = data[NotificationsConstants.LikeNotificationConstants.LIKE_ID]
|
||||
val postId = data[NotificationsConstants.LikeNotificationConstants.POST_ID]
|
||||
val authorId = data[NotificationsConstants.LikeNotificationConstants.AUTHOR_ID]?.toIntOrNull()
|
||||
val authorName = data[NotificationsConstants.LikeNotificationConstants.AUTHOR_NAME]
|
||||
|
||||
|
||||
val imageUrl = authorId?.let { UrlGen.userProfileImage(it, true) }
|
||||
|
||||
Log.d(LOG_TAG, data.toString())
|
||||
|
||||
val imageRequest = ImageRequest
|
||||
.Builder(this)
|
||||
.data(imageUrl)
|
||||
.fallback(R.drawable.baseline_person_24)
|
||||
.target { drawable ->
|
||||
val notificationBuilder = NotificationCompat.Builder(this, MyApplication.LIKES_NOTIFICATION_CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setContentTitle(getString(R.string.like_notification_title, authorName ?: ""))
|
||||
.setContentText(getString(R.string.like_notification_text))
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.setLargeIcon(drawable.toBitmap())
|
||||
|
||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||
return@target
|
||||
}
|
||||
|
||||
Log.v(LOG_TAG, "Notification id: $notificationId")
|
||||
// notificationId should never be null
|
||||
if(notificationId == null) {
|
||||
return@target
|
||||
}
|
||||
NotificationManagerCompat.from(this).run {
|
||||
relatedNotifications?.forEach {
|
||||
it.toIntOrNull()?.let { relatedNotificationId -> cancel(relatedNotificationId) }
|
||||
}
|
||||
|
||||
|
||||
notify(notificationId, notificationBuilder.build())
|
||||
}
|
||||
}.build()
|
||||
|
||||
|
||||
CoilImageLoader.getImageLoader(this).enqueue(imageRequest)
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
package com.isolaatti.push_notifications
|
||||
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody
|
||||
import retrofit2.Call
|
||||
import retrofit2.http.Multipart
|
||||
import retrofit2.http.PUT
|
||||
@ -9,6 +11,6 @@ interface PushNotificationsApi {
|
||||
|
||||
@PUT("/api/push_notifications/register_device")
|
||||
@Multipart
|
||||
fun registerDevice(@Part("token") token: String): Call<Unit>
|
||||
fun registerDevice(@Part("token") token: RequestBody): Call<Unit>
|
||||
|
||||
}
|
||||
BIN
app/src/main/res/drawable-hdpi/ic_notification.png
Normal file
BIN
app/src/main/res/drawable-hdpi/ic_notification.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 420 B |
BIN
app/src/main/res/drawable-mdpi/ic_notification.png
Normal file
BIN
app/src/main/res/drawable-mdpi/ic_notification.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 338 B |
BIN
app/src/main/res/drawable-xhdpi/ic_notification.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_notification.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 534 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_notification.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/ic_notification.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 751 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_notification.png
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_notification.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 974 B |
@ -189,4 +189,8 @@
|
||||
<string name="push_notifications_dialog_title">Push notifications</string>
|
||||
<string name="push_notifications_dialog_message">Receive notifications to stay informed about your profile activity</string>
|
||||
<string name="push_notifications_dialog_rejected_message">You won\'t receive notifications. You can change this on your device settings.</string>
|
||||
<string name="likes_notification_channel">Likes notifications</string>
|
||||
<string name="likes_notification_channel_description">Get notified when someone likes your posts.</string>
|
||||
<string name="like_notification_title">%s claps to your post</string>
|
||||
<string name="like_notification_text">Tap this notification to go to the post.</string>
|
||||
</resources>
|
||||
Loading…
x
Reference in New Issue
Block a user