feat: reply notifications

This commit is contained in:
rebelonion 2024-02-27 02:13:06 -06:00
parent a8bd9ef97b
commit efe5f546a2
8 changed files with 316 additions and 71 deletions

View file

@ -0,0 +1,71 @@
package ani.dantotsu.notifications
import ani.dantotsu.client
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
class MediaNameFetch {
companion object {
private fun queryBuilder(mediaIds: List<Int>): String {
var query = "{"
mediaIds.forEachIndexed { index, mediaId ->
query += """
media$index: Media(id: $mediaId) {
id
title {
romaji
}
}
""".trimIndent()
}
query += "}"
return query
}
suspend fun fetchMediaTitles(ids: List<Int>): Map<Int, String> {
return try {
val url = "https://graphql.anilist.co/"
val data = mapOf(
"query" to queryBuilder(ids),
)
withContext(Dispatchers.IO) {
val response = client.post(
url,
headers = mapOf(
"Content-Type" to "application/json",
"Accept" to "application/json"
),
data = data
)
val mediaResponse = parseMediaResponseWithGson(response.text)
val mediaMap = mutableMapOf<Int, String>()
mediaResponse.data.forEach { (_, mediaItem) ->
mediaMap[mediaItem.id] = mediaItem.title.romaji
}
mediaMap
}
} catch (e: Exception) {
val errorMap = mutableMapOf<Int, String>()
ids.forEach { errorMap[it] = "Unknown" }
errorMap
}
}
private fun parseMediaResponseWithGson(response: String): MediaResponse {
val gson = Gson()
val type = object : TypeToken<MediaResponse>() {}.type
return gson.fromJson(response, type)
}
data class MediaResponse(val data: Map<String, MediaItem>)
data class MediaItem(
val id: Int,
val title: MediaTitle
)
data class MediaTitle(val romaji: String)
}
}

View file

@ -0,0 +1,100 @@
package ani.dantotsu.notifications
import android.Manifest
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.work.Worker
import androidx.work.WorkerParameters
import ani.dantotsu.R
import ani.dantotsu.connections.comments.CommentsAPI
import ani.dantotsu.media.MediaDetailsActivity
import eu.kanade.tachiyomi.data.notification.Notifications
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class NotificationWorker(appContext: Context, workerParams: WorkerParameters) :
Worker(appContext, workerParams) {
override fun doWork(): Result {
val scope = CoroutineScope(Dispatchers.IO)
scope.launch {
val notifications = CommentsAPI.getNotifications()
val mediaIds = notifications?.notifications?.map { it.mediaId }
val names = MediaNameFetch.fetchMediaTitles(mediaIds ?: emptyList())
notifications?.notifications?.forEach {
val title = "New Comment Reply"
val mediaName = names[it.mediaId] ?: "Unknown"
val message = "${it.username} replied to your comment in $mediaName"
val notification = createNotification(
NotificationType.COMMENT_REPLY,
message,
title,
it.mediaId,
it.commentId
)
if (ActivityCompat.checkSelfPermission(
applicationContext,
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED
) {
NotificationManagerCompat.from(applicationContext)
.notify(
NotificationType.COMMENT_REPLY.id,
Notifications.ID_COMMENT_REPLY,
notification
)
}
}
}
return Result.success()
}
private fun createNotification(
notificationType: NotificationType,
message: String,
title: String,
mediaId: Int,
commentId: Int
): android.app.Notification {
val notification = when (notificationType) {
NotificationType.COMMENT_REPLY -> {
val intent = Intent(applicationContext, MediaDetailsActivity::class.java).apply {
putExtra("FRAGMENT_TO_LOAD", "COMMENTS")
putExtra("mediaId", mediaId)
putExtra("commentId", commentId)
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent = PendingIntent.getActivity(
applicationContext,
0,
intent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
val builder = NotificationCompat.Builder(applicationContext, notificationType.id)
.setContentTitle(title)
.setContentText(message)
.setSmallIcon(R.drawable.ic_round_comment_24)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
builder.build()
}
}
return notification
}
enum class NotificationType(val id: String) {
COMMENT_REPLY(Notifications.CHANNEL_COMMENTS),
}
companion object {
const val WORK_NAME = "ani.dantotsu.notifications.NotificationWorker"
}
}