Skip to content

Commit

Permalink
feat: reply notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
rebelonion committed Feb 27, 2024
1 parent a8bd9ef commit efe5f54
Show file tree
Hide file tree
Showing 8 changed files with 316 additions and 71 deletions.
16 changes: 16 additions & 0 deletions app/src/main/java/ani/dantotsu/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import android.content.Context
import android.os.Bundle
import androidx.multidex.MultiDex
import androidx.multidex.MultiDexApplication
import androidx.work.Constraints
import androidx.work.PeriodicWorkRequest
import ani.dantotsu.aniyomi.anime.custom.AppModule
import ani.dantotsu.aniyomi.anime.custom.PreferenceModule
import ani.dantotsu.connections.comments.CommentsAPI
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.notifications.NotificationWorker
import ani.dantotsu.others.DisabledReports
import ani.dantotsu.parsers.AnimeSources
import ani.dantotsu.parsers.MangaSources
Expand Down Expand Up @@ -115,6 +118,19 @@ class App : MultiDexApplication() {
commentsScope.launch {
CommentsAPI.fetchAuthToken()
}

val constraints = Constraints.Builder()
.setRequiredNetworkType(androidx.work.NetworkType.CONNECTED)
.build()
val recurringWork = PeriodicWorkRequest.Builder(NotificationWorker::class.java,
15, java.util.concurrent.TimeUnit.MINUTES)
.setConstraints(constraints)
.build()
androidx.work.WorkManager.getInstance(this).enqueueUniquePeriodicWork(
NotificationWorker.WORK_NAME,
androidx.work.ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
recurringWork
)
}


Expand Down
60 changes: 60 additions & 0 deletions app/src/main/java/ani/dantotsu/connections/comments/CommentsAPI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,28 @@ object CommentsAPI {
return parsed
}

suspend fun getSingleComment(id: Int): Comment? {
val url = "$address/comments/$id"
val request = requestBuilder()
val json = try {
request.get(url)
} catch (e: IOException) {
snackString("Failed to fetch comment")
return null
}
if (!json.text.startsWith("{")) return null
val res = json.code == 200
if (!res && json.code != 404) {
errorReason(json.code, json.text)
}
val parsed = try {
Json.decodeFromString<Comment>(json.text)
} catch (e: Exception) {
return null
}
return parsed
}

suspend fun vote(commentId: Int, voteType: Int): Boolean {
val url = "$address/comments/vote/$commentId/$voteType"
val request = requestBuilder()
Expand Down Expand Up @@ -212,6 +234,27 @@ object CommentsAPI {
return res
}

suspend fun getNotifications(): NotificationResponse? {
val url = "$address/notification/reply"
val request = requestBuilder()
val json = try {
request.get(url)
} catch (e: IOException) {
return null
}
if (!json.text.startsWith("{")) return null
val res = json.code == 200
if (!res) {
return null
}
val parsed = try {
Json.decodeFromString<NotificationResponse>(json.text)
} catch (e: Exception) {
return null
}
return parsed
}

suspend fun fetchAuthToken() {
if (authToken != null) return
val MAX_RETRIES = 5
Expand Down Expand Up @@ -311,6 +354,23 @@ data class ErrorResponse(
val message: String
)

@Serializable
data class NotificationResponse(
@SerialName("notifications")
val notifications: List<Notification>
)

@Serializable
data class Notification(
@SerialName("username")
val username: String,
@SerialName("media_id")
val mediaId: Int,
@SerialName("comment_id")
val commentId: Int
)


@Serializable
data class AuthResponse(
@SerialName("authToken")
Expand Down
25 changes: 21 additions & 4 deletions app/src/main/java/ani/dantotsu/media/MediaDetailsActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import kotlin.math.abs


Expand All @@ -72,6 +74,15 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
var media: Media = intent.getSerialized("media") ?: mediaSingleton ?: emptyMedia()
val id = intent.getIntExtra("mediaId", -1)
if (id != -1) {
runBlocking {
withContext(Dispatchers.IO) {
media =
Anilist.query.getMedia(id, false) ?: emptyMedia()
}
}
}
if (media.name == "No media found") {
snackString(media.name)
onBackPressedDispatcher.onBackPressed()
Expand Down Expand Up @@ -314,19 +325,19 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
progress()
}
}

adult = media.isAdult
tabLayout.menu.clear()
if (media.anime != null) {
viewPager.adapter =
ViewPagerAdapter(supportFragmentManager, lifecycle, SupportedMedia.ANIME, media)
ViewPagerAdapter(supportFragmentManager, lifecycle, SupportedMedia.ANIME, media, intent.getIntExtra("commentId", -1))
tabLayout.inflateMenu(R.menu.anime_menu_detail)
} else if (media.manga != null) {
viewPager.adapter = ViewPagerAdapter(
supportFragmentManager,
lifecycle,
if (media.format == "NOVEL") SupportedMedia.NOVEL else SupportedMedia.MANGA,
media
media,
intent.getIntExtra("commentId", -1)
)
if (media.format == "NOVEL") {
tabLayout.inflateMenu(R.menu.novel_menu_detail)
Expand Down Expand Up @@ -358,6 +369,10 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
model.continueMedia = PrefManager.getVal(PrefName.ContinueMedia)
selected = 1
}
val frag = intent.getStringExtra("FRAGMENT_TO_LOAD")
if (frag != null) {
selected = 2
}

val live = Refresh.activity.getOrPut(this.hashCode()) { MutableLiveData(true) }
live.observe(this) {
Expand Down Expand Up @@ -417,7 +432,8 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
fragmentManager: FragmentManager,
lifecycle: Lifecycle,
private val mediaType: SupportedMedia,
private val media: Media
private val media: Media,
private val commentId: Int
) :
FragmentStateAdapter(fragmentManager, lifecycle) {

Expand All @@ -435,6 +451,7 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
val bundle = Bundle()
bundle.putInt("mediaId", media.id)
bundle.putString("mediaName", media.mainName())
if (commentId != -1) bundle.putInt("commentId", commentId)
fragment.arguments = bundle
fragment
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,12 @@ class CommentsFragment : Fragment() {
binding.commentsList.layoutManager = LinearLayoutManager(activity)

lifecycleScope.launch {
loadAndDisplayComments()
val commentId = arguments?.getInt("commentId")
if (commentId != null && commentId > 0) {
loadSingleComment(commentId)
} else {
loadAndDisplayComments()
}
}

binding.commentSort.setOnClickListener { view ->
Expand Down Expand Up @@ -395,6 +400,31 @@ class CommentsFragment : Fragment() {
adapter.add(section)
}

private suspend fun loadSingleComment(commentId: Int) {
binding.commentsProgressBar.visibility = View.VISIBLE
binding.commentsList.visibility = View.GONE
adapter.clear()
section.clear()

val comment = withContext(Dispatchers.IO) {
CommentsAPI.getSingleComment(commentId)
}
if (comment != null) {
withContext(Dispatchers.Main) {
section.add(
CommentItem(
comment,
buildMarkwon(),
section,
this@CommentsFragment,
backgroundColor,
0
)
)
}
}
}

private fun sortComments(comments: List<Comment>?): List<Comment> {
if (comments == null) return emptyList()
return when (PrefManager.getVal(PrefName.CommentSortOrder, "newest")) {
Expand Down
71 changes: 71 additions & 0 deletions app/src/main/java/ani/dantotsu/notifications/MediaNameFetch.kt
Original file line number Diff line number Diff line change
@@ -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)

}
}
Loading

0 comments on commit efe5f54

Please sign in to comment.