diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9b52dfa..7b7d472 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -30,10 +30,11 @@ + android:parentActivityName=".home.HomeActivity"/> - + diff --git a/app/src/main/java/com/isolaatti/notifications/domain/Notification.kt b/app/src/main/java/com/isolaatti/notifications/domain/Notification.kt index d769aba..ab8a884 100644 --- a/app/src/main/java/com/isolaatti/notifications/domain/Notification.kt +++ b/app/src/main/java/com/isolaatti/notifications/domain/Notification.kt @@ -41,7 +41,7 @@ class LikeNotification(id: Long, date: ZonedDateTime, userId: Int, read: Boolean class FollowNotification(id: Long, date: ZonedDateTime, userId: Int, read: Boolean) : Notification(id, date, userId, read) { companion object { - const val TYPE = "follow" + const val TYPE = "follower" } override fun ingestPayload(notificationPayload: NotificationPayload) { diff --git a/app/src/main/java/com/isolaatti/posting/posts/viewer/ui/PostViewerActivity.kt b/app/src/main/java/com/isolaatti/posting/posts/viewer/ui/PostViewerActivity.kt index 643855c..88d54f9 100644 --- a/app/src/main/java/com/isolaatti/posting/posts/viewer/ui/PostViewerActivity.kt +++ b/app/src/main/java/com/isolaatti/posting/posts/viewer/ui/PostViewerActivity.kt @@ -1,9 +1,12 @@ package com.isolaatti.posting.posts.viewer.ui +import android.app.PendingIntent import android.content.Context import android.content.Intent import android.os.Bundle +import android.util.Log import androidx.activity.viewModels +import androidx.core.app.TaskStackBuilder import androidx.core.content.res.ResourcesCompat import coil.imageLoader import coil.load @@ -28,10 +31,23 @@ import kotlinx.coroutines.launch class PostViewerActivity : IsolaattiBaseActivity() { companion object { const val POST_ID = "postId" - fun startActivity(context: Context, postId: Long) { - context.startActivity(Intent(context, PostViewerActivity::class.java).apply { + const val LOG_TAG = "PostViewerActivity" + + fun getIntent(context: Context, postId: Long): Intent { + return Intent(context, PostViewerActivity::class.java).apply { putExtra(POST_ID, postId) - }) + } + } + fun startActivity(context: Context, postId: Long) { + context.startActivity(getIntent(context, postId)) + } + + fun getPendingIntent(context: Context, postId: Long): PendingIntent? { + return TaskStackBuilder.create(context).run { + addNextIntentWithParentStack(Companion.getIntent(context, postId)) + + getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + } } } @@ -106,9 +122,21 @@ class PostViewerActivity : IsolaattiBaseActivity() { } } + + override fun onNewIntent(intent: Intent?) { + super.onNewIntent(intent) + + intent?.getLongExtra(POST_ID, 0)?.let { + postId = it + viewModel.postId = postId + viewModel.getPost() + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) postId = intent.getLongExtra(POST_ID, 0) + Log.d(LOG_TAG, "Post id: $postId") binding = ActivityPostViewerBinding.inflate(layoutInflater) markwon = Markwon.builder(this) diff --git a/app/src/main/java/com/isolaatti/profile/ui/ProfileActivity.kt b/app/src/main/java/com/isolaatti/profile/ui/ProfileActivity.kt index 2adf816..b2d2125 100644 --- a/app/src/main/java/com/isolaatti/profile/ui/ProfileActivity.kt +++ b/app/src/main/java/com/isolaatti/profile/ui/ProfileActivity.kt @@ -1,8 +1,10 @@ package com.isolaatti.profile.ui +import android.app.PendingIntent import android.content.Context import android.content.Intent import android.os.Bundle +import androidx.core.app.TaskStackBuilder import com.isolaatti.common.IsolaattiBaseActivity import com.isolaatti.databinding.ActivityProfileBinding import dagger.hilt.android.AndroidEntryPoint @@ -22,10 +24,22 @@ class ProfileActivity : IsolaattiBaseActivity() { companion object { const val EXTRA_USER_ID = "user_id" - fun startActivity(context: Context, userId: Int) { - context.startActivity(Intent(context, ProfileActivity::class.java).apply { + fun getIntent(context: Context, userId: Int): Intent { + return Intent(context, ProfileActivity::class.java).apply { putExtra(EXTRA_USER_ID, userId) - }) + } + } + + fun startActivity(context: Context, userId: Int) { + context.startActivity(getIntent(context, userId)) + } + + fun getPendingIntent(context: Context, userId: Int): PendingIntent? { + return TaskStackBuilder.create(context).run { + addNextIntentWithParentStack(getIntent(context, userId)) + + getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/push_notifications/FcmService.kt b/app/src/main/java/com/isolaatti/push_notifications/FcmService.kt index eeb72cb..0a47e43 100644 --- a/app/src/main/java/com/isolaatti/push_notifications/FcmService.kt +++ b/app/src/main/java/com/isolaatti/push_notifications/FcmService.kt @@ -7,23 +7,23 @@ 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 com.isolaatti.MyApplication import com.isolaatti.R import com.isolaatti.common.CoilImageLoader +import com.isolaatti.notifications.domain.FollowNotification import com.isolaatti.notifications.domain.LikeNotification +import com.isolaatti.posting.posts.viewer.ui.PostViewerActivity +import com.isolaatti.profile.ui.ProfileActivity 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 @@ -45,6 +45,11 @@ class FcmService : FirebaseMessagingService() { const val AUTHOR_ID = "authorId" const val AUTHOR_NAME = "authorName" } + + object NewFollowerNotificationConstants { + const val FOLLOWER_USER_ID = "followerUserId" + const val FOLLOWER_NAME = "followerName" + } } } @@ -67,6 +72,7 @@ class FcmService : FirebaseMessagingService() { when(type) { LikeNotification.TYPE -> showLikeNotification(message.data) + FollowNotification.TYPE -> showNewFollowerNotification(message.data) else -> { Log.i(LOG_TAG, "Not showing notification of unknown type: ${message.data}") @@ -78,11 +84,18 @@ class FcmService : FirebaseMessagingService() { 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 postId = data[NotificationsConstants.LikeNotificationConstants.POST_ID]?.toLongOrNull() val authorId = data[NotificationsConstants.LikeNotificationConstants.AUTHOR_ID]?.toIntOrNull() val authorName = data[NotificationsConstants.LikeNotificationConstants.AUTHOR_NAME] + // notificationId should never be null + if(notificationId == null) { + Log.e(LOG_TAG, "notification id is null") + return + } + Log.v(LOG_TAG, "Notification id: $notificationId") + val imageUrl = authorId?.let { UrlGen.userProfileImage(it, true) } Log.d(LOG_TAG, data.toString()) @@ -98,16 +111,18 @@ class FcmService : FirebaseMessagingService() { .setContentText(getString(R.string.like_notification_text)) .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setLargeIcon(drawable.toBitmap()) + .setAutoCancel(true) + + Log.v(LOG_TAG, "Post liked: $postId") + + if(postId != null) { + notificationBuilder.setContentIntent(PostViewerActivity.getPendingIntent(this, postId)) + } 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) } @@ -121,4 +136,61 @@ class FcmService : FirebaseMessagingService() { CoilImageLoader.getImageLoader(this).enqueue(imageRequest) } + + private fun showNewFollowerNotification(data: Map) { + val notificationId = data[NotificationsConstants.NOTIFICATION_ID]?.toIntOrNull() + val relatedNotifications = data[NotificationsConstants.RELATED_NOTIFICATIONS]?.trimStart('[')?.trimEnd(']')?.split(",") + val followerUserId = data[NotificationsConstants.NewFollowerNotificationConstants.FOLLOWER_USER_ID]?.toIntOrNull() + val followerName = data[NotificationsConstants.NewFollowerNotificationConstants.FOLLOWER_NAME] + + // notificationId should never be null + if(notificationId == null) { + Log.e(LOG_TAG, "notification id is null") + return + } + + if(followerUserId == null) { + Log.e(LOG_TAG, "followerUserId is not present or is not valid") + } + + val imageUrl = followerUserId?.let { UrlGen.userProfileImage(it, true) } + + 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.new_follower_notification_title, followerName ?: "")) + .setContentText(getString(R.string.new_follower_notification_text)) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .setLargeIcon(drawable.toBitmap()) + .setAutoCancel(true) + + if(followerUserId != null) { + notificationBuilder.setContentIntent(ProfileActivity.getPendingIntent(this, followerUserId)) + } + + + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { + return@target + } + + + + NotificationManagerCompat.from(this).run { + relatedNotifications?.forEach { + it.toIntOrNull()?.let { relatedNotificationId -> cancel(relatedNotificationId) } + } + + + notify(notificationId, notificationBuilder.build()) + } + }.build() + + + CoilImageLoader.getImageLoader(this).enqueue(imageRequest) + + } } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4bceca9..e8bfa31 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -193,4 +193,6 @@ Get notified when someone likes your posts. %s claps to your post Tap this notification to go to the post. + %s is now following you + Tap this notification to see their profile. \ No newline at end of file