feat: reply notifications
This commit is contained in:
parent
a8bd9ef97b
commit
efe5f546a2
8 changed files with 316 additions and 71 deletions
|
@ -6,10 +6,13 @@ import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.multidex.MultiDex
|
import androidx.multidex.MultiDex
|
||||||
import androidx.multidex.MultiDexApplication
|
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.AppModule
|
||||||
import ani.dantotsu.aniyomi.anime.custom.PreferenceModule
|
import ani.dantotsu.aniyomi.anime.custom.PreferenceModule
|
||||||
import ani.dantotsu.connections.comments.CommentsAPI
|
import ani.dantotsu.connections.comments.CommentsAPI
|
||||||
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
||||||
|
import ani.dantotsu.notifications.NotificationWorker
|
||||||
import ani.dantotsu.others.DisabledReports
|
import ani.dantotsu.others.DisabledReports
|
||||||
import ani.dantotsu.parsers.AnimeSources
|
import ani.dantotsu.parsers.AnimeSources
|
||||||
import ani.dantotsu.parsers.MangaSources
|
import ani.dantotsu.parsers.MangaSources
|
||||||
|
@ -115,6 +118,19 @@ class App : MultiDexApplication() {
|
||||||
commentsScope.launch {
|
commentsScope.launch {
|
||||||
CommentsAPI.fetchAuthToken()
|
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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,28 @@ object CommentsAPI {
|
||||||
return parsed
|
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 {
|
suspend fun vote(commentId: Int, voteType: Int): Boolean {
|
||||||
val url = "$address/comments/vote/$commentId/$voteType"
|
val url = "$address/comments/vote/$commentId/$voteType"
|
||||||
val request = requestBuilder()
|
val request = requestBuilder()
|
||||||
|
@ -212,6 +234,27 @@ object CommentsAPI {
|
||||||
return res
|
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() {
|
suspend fun fetchAuthToken() {
|
||||||
if (authToken != null) return
|
if (authToken != null) return
|
||||||
val MAX_RETRIES = 5
|
val MAX_RETRIES = 5
|
||||||
|
@ -311,6 +354,23 @@ data class ErrorResponse(
|
||||||
val message: String
|
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
|
@Serializable
|
||||||
data class AuthResponse(
|
data class AuthResponse(
|
||||||
@SerialName("authToken")
|
@SerialName("authToken")
|
||||||
|
|
|
@ -55,6 +55,8 @@ import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,6 +74,15 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
var media: Media = intent.getSerialized("media") ?: mediaSingleton ?: emptyMedia()
|
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") {
|
if (media.name == "No media found") {
|
||||||
snackString(media.name)
|
snackString(media.name)
|
||||||
onBackPressedDispatcher.onBackPressed()
|
onBackPressedDispatcher.onBackPressed()
|
||||||
|
@ -314,19 +325,19 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||||
progress()
|
progress()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
adult = media.isAdult
|
adult = media.isAdult
|
||||||
tabLayout.menu.clear()
|
tabLayout.menu.clear()
|
||||||
if (media.anime != null) {
|
if (media.anime != null) {
|
||||||
viewPager.adapter =
|
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)
|
tabLayout.inflateMenu(R.menu.anime_menu_detail)
|
||||||
} else if (media.manga != null) {
|
} else if (media.manga != null) {
|
||||||
viewPager.adapter = ViewPagerAdapter(
|
viewPager.adapter = ViewPagerAdapter(
|
||||||
supportFragmentManager,
|
supportFragmentManager,
|
||||||
lifecycle,
|
lifecycle,
|
||||||
if (media.format == "NOVEL") SupportedMedia.NOVEL else SupportedMedia.MANGA,
|
if (media.format == "NOVEL") SupportedMedia.NOVEL else SupportedMedia.MANGA,
|
||||||
media
|
media,
|
||||||
|
intent.getIntExtra("commentId", -1)
|
||||||
)
|
)
|
||||||
if (media.format == "NOVEL") {
|
if (media.format == "NOVEL") {
|
||||||
tabLayout.inflateMenu(R.menu.novel_menu_detail)
|
tabLayout.inflateMenu(R.menu.novel_menu_detail)
|
||||||
|
@ -358,6 +369,10 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||||
model.continueMedia = PrefManager.getVal(PrefName.ContinueMedia)
|
model.continueMedia = PrefManager.getVal(PrefName.ContinueMedia)
|
||||||
selected = 1
|
selected = 1
|
||||||
}
|
}
|
||||||
|
val frag = intent.getStringExtra("FRAGMENT_TO_LOAD")
|
||||||
|
if (frag != null) {
|
||||||
|
selected = 2
|
||||||
|
}
|
||||||
|
|
||||||
val live = Refresh.activity.getOrPut(this.hashCode()) { MutableLiveData(true) }
|
val live = Refresh.activity.getOrPut(this.hashCode()) { MutableLiveData(true) }
|
||||||
live.observe(this) {
|
live.observe(this) {
|
||||||
|
@ -417,7 +432,8 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||||
fragmentManager: FragmentManager,
|
fragmentManager: FragmentManager,
|
||||||
lifecycle: Lifecycle,
|
lifecycle: Lifecycle,
|
||||||
private val mediaType: SupportedMedia,
|
private val mediaType: SupportedMedia,
|
||||||
private val media: Media
|
private val media: Media,
|
||||||
|
private val commentId: Int
|
||||||
) :
|
) :
|
||||||
FragmentStateAdapter(fragmentManager, lifecycle) {
|
FragmentStateAdapter(fragmentManager, lifecycle) {
|
||||||
|
|
||||||
|
@ -435,6 +451,7 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
bundle.putInt("mediaId", media.id)
|
bundle.putInt("mediaId", media.id)
|
||||||
bundle.putString("mediaName", media.mainName())
|
bundle.putString("mediaName", media.mainName())
|
||||||
|
if (commentId != -1) bundle.putInt("commentId", commentId)
|
||||||
fragment.arguments = bundle
|
fragment.arguments = bundle
|
||||||
fragment
|
fragment
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,12 @@ class CommentsFragment : Fragment() {
|
||||||
binding.commentsList.layoutManager = LinearLayoutManager(activity)
|
binding.commentsList.layoutManager = LinearLayoutManager(activity)
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
loadAndDisplayComments()
|
val commentId = arguments?.getInt("commentId")
|
||||||
|
if (commentId != null && commentId > 0) {
|
||||||
|
loadSingleComment(commentId)
|
||||||
|
} else {
|
||||||
|
loadAndDisplayComments()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.commentSort.setOnClickListener { view ->
|
binding.commentSort.setOnClickListener { view ->
|
||||||
|
@ -395,6 +400,31 @@ class CommentsFragment : Fragment() {
|
||||||
adapter.add(section)
|
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> {
|
private fun sortComments(comments: List<Comment>?): List<Comment> {
|
||||||
if (comments == null) return emptyList()
|
if (comments == null) return emptyList()
|
||||||
return when (PrefManager.getVal(PrefName.CommentSortOrder, "newest")) {
|
return when (PrefManager.getVal(PrefName.CommentSortOrder, "newest")) {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,6 +33,7 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
|
||||||
MangaSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
MangaSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
||||||
MangaSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
|
MangaSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
|
||||||
NovelSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
NovelSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
||||||
|
NotificationInterval(Pref(Location.General, Int::class, 0)),
|
||||||
|
|
||||||
//User Interface
|
//User Interface
|
||||||
UseOLED(Pref(Location.UI, Boolean::class, false)),
|
UseOLED(Pref(Location.UI, Boolean::class, false)),
|
||||||
|
|
|
@ -19,18 +19,6 @@ object Notifications {
|
||||||
const val CHANNEL_COMMON = "common_channel"
|
const val CHANNEL_COMMON = "common_channel"
|
||||||
const val ID_DOWNLOAD_IMAGE = 2
|
const val ID_DOWNLOAD_IMAGE = 2
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification channel and ids used by the library updater.
|
|
||||||
*/
|
|
||||||
private const val GROUP_LIBRARY = "group_library"
|
|
||||||
const val CHANNEL_LIBRARY_PROGRESS = "library_progress_channel"
|
|
||||||
const val ID_LIBRARY_PROGRESS = -101
|
|
||||||
const val ID_LIBRARY_SIZE_WARNING = -103
|
|
||||||
const val CHANNEL_LIBRARY_ERROR = "library_errors_channel"
|
|
||||||
const val ID_LIBRARY_ERROR = -102
|
|
||||||
const val CHANNEL_LIBRARY_SKIPPED = "library_skipped_channel"
|
|
||||||
const val ID_LIBRARY_SKIPPED = -104
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notification channel and ids used by the downloader.
|
* Notification channel and ids used by the downloader.
|
||||||
*/
|
*/
|
||||||
|
@ -51,23 +39,19 @@ object Notifications {
|
||||||
const val GROUP_NEW_CHAPTERS = "eu.kanade.tachiyomi.NEW_CHAPTERS"
|
const val GROUP_NEW_CHAPTERS = "eu.kanade.tachiyomi.NEW_CHAPTERS"
|
||||||
const val GROUP_NEW_EPISODES = "eu.kanade.tachiyomi.NEW_EPISODES"
|
const val GROUP_NEW_EPISODES = "eu.kanade.tachiyomi.NEW_EPISODES"
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification channel and ids used by the backup/restore system.
|
|
||||||
*/
|
|
||||||
private const val GROUP_BACKUP_RESTORE = "group_backup_restore"
|
|
||||||
const val CHANNEL_BACKUP_RESTORE_PROGRESS = "backup_restore_progress_channel"
|
|
||||||
const val ID_BACKUP_PROGRESS = -501
|
|
||||||
const val ID_RESTORE_PROGRESS = -503
|
|
||||||
const val CHANNEL_BACKUP_RESTORE_COMPLETE = "backup_restore_complete_channel_v2"
|
|
||||||
const val ID_BACKUP_COMPLETE = -502
|
|
||||||
const val ID_RESTORE_COMPLETE = -504
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notification channel used for Incognito Mode
|
* Notification channel used for Incognito Mode
|
||||||
*/
|
*/
|
||||||
const val CHANNEL_INCOGNITO_MODE = "incognito_mode_channel"
|
const val CHANNEL_INCOGNITO_MODE = "incognito_mode_channel"
|
||||||
const val ID_INCOGNITO_MODE = -701
|
const val ID_INCOGNITO_MODE = -701
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification channel used for comment notifications
|
||||||
|
*/
|
||||||
|
const val CHANNEL_COMMENTS = "comments_channel"
|
||||||
|
const val ID_COMMENT_REPLY = -801
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notification channel and ids used for app and extension updates.
|
* Notification channel and ids used for app and extension updates.
|
||||||
*/
|
*/
|
||||||
|
@ -88,6 +72,12 @@ object Notifications {
|
||||||
"updates_ext_channel",
|
"updates_ext_channel",
|
||||||
"downloader_cache_renewal",
|
"downloader_cache_renewal",
|
||||||
"crash_logs_channel",
|
"crash_logs_channel",
|
||||||
|
"backup_restore_complete_channel_v2",
|
||||||
|
"backup_restore_progress_channel",
|
||||||
|
"group_backup_restore",
|
||||||
|
"library_skipped_channel",
|
||||||
|
"library_errors_channel",
|
||||||
|
"library_progress_channel",
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -102,43 +92,11 @@ object Notifications {
|
||||||
// Delete old notification channels
|
// Delete old notification channels
|
||||||
deprecatedChannels.forEach(notificationManager::deleteNotificationChannel)
|
deprecatedChannels.forEach(notificationManager::deleteNotificationChannel)
|
||||||
|
|
||||||
notificationManager.createNotificationChannelGroupsCompat(
|
|
||||||
listOf(
|
|
||||||
buildNotificationChannelGroup(GROUP_BACKUP_RESTORE) {
|
|
||||||
setName("Backup & Restore")
|
|
||||||
},
|
|
||||||
buildNotificationChannelGroup(GROUP_DOWNLOADER) {
|
|
||||||
setName("Downloader")
|
|
||||||
},
|
|
||||||
buildNotificationChannelGroup(GROUP_LIBRARY) {
|
|
||||||
setName("Library")
|
|
||||||
},
|
|
||||||
buildNotificationChannelGroup(GROUP_APK_UPDATES) {
|
|
||||||
setName("App & Extension Updates")
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
notificationManager.createNotificationChannelsCompat(
|
notificationManager.createNotificationChannelsCompat(
|
||||||
listOf(
|
listOf(
|
||||||
buildNotificationChannel(CHANNEL_COMMON, IMPORTANCE_LOW) {
|
buildNotificationChannel(CHANNEL_COMMON, IMPORTANCE_LOW) {
|
||||||
setName("Common")
|
setName("Common")
|
||||||
},
|
},
|
||||||
buildNotificationChannel(CHANNEL_LIBRARY_PROGRESS, IMPORTANCE_LOW) {
|
|
||||||
setName("Library Progress")
|
|
||||||
setGroup(GROUP_LIBRARY)
|
|
||||||
setShowBadge(false)
|
|
||||||
},
|
|
||||||
buildNotificationChannel(CHANNEL_LIBRARY_ERROR, IMPORTANCE_LOW) {
|
|
||||||
setName("Library Errors")
|
|
||||||
setGroup(GROUP_LIBRARY)
|
|
||||||
setShowBadge(false)
|
|
||||||
},
|
|
||||||
buildNotificationChannel(CHANNEL_LIBRARY_SKIPPED, IMPORTANCE_LOW) {
|
|
||||||
setName("Library Skipped")
|
|
||||||
setGroup(GROUP_LIBRARY)
|
|
||||||
setShowBadge(false)
|
|
||||||
},
|
|
||||||
buildNotificationChannel(CHANNEL_NEW_CHAPTERS_EPISODES, IMPORTANCE_DEFAULT) {
|
buildNotificationChannel(CHANNEL_NEW_CHAPTERS_EPISODES, IMPORTANCE_DEFAULT) {
|
||||||
setName("New Chapters & Episodes")
|
setName("New Chapters & Episodes")
|
||||||
},
|
},
|
||||||
|
@ -152,20 +110,12 @@ object Notifications {
|
||||||
setGroup(GROUP_DOWNLOADER)
|
setGroup(GROUP_DOWNLOADER)
|
||||||
setShowBadge(false)
|
setShowBadge(false)
|
||||||
},
|
},
|
||||||
buildNotificationChannel(CHANNEL_BACKUP_RESTORE_PROGRESS, IMPORTANCE_LOW) {
|
|
||||||
setName("Backup & Restore Progress")
|
|
||||||
setGroup(GROUP_BACKUP_RESTORE)
|
|
||||||
setShowBadge(false)
|
|
||||||
},
|
|
||||||
buildNotificationChannel(CHANNEL_BACKUP_RESTORE_COMPLETE, IMPORTANCE_HIGH) {
|
|
||||||
setName("Backup & Restore Complete")
|
|
||||||
setGroup(GROUP_BACKUP_RESTORE)
|
|
||||||
setShowBadge(false)
|
|
||||||
setSound(null, null)
|
|
||||||
},
|
|
||||||
buildNotificationChannel(CHANNEL_INCOGNITO_MODE, IMPORTANCE_LOW) {
|
buildNotificationChannel(CHANNEL_INCOGNITO_MODE, IMPORTANCE_LOW) {
|
||||||
setName("Incognito Mode")
|
setName("Incognito Mode")
|
||||||
},
|
},
|
||||||
|
buildNotificationChannel(CHANNEL_COMMENTS, IMPORTANCE_HIGH) {
|
||||||
|
setName("Comments")
|
||||||
|
},
|
||||||
buildNotificationChannel(CHANNEL_APP_UPDATE, IMPORTANCE_DEFAULT) {
|
buildNotificationChannel(CHANNEL_APP_UPDATE, IMPORTANCE_DEFAULT) {
|
||||||
setGroup(GROUP_APK_UPDATES)
|
setGroup(GROUP_APK_UPDATES)
|
||||||
setName("App Updates")
|
setName("App Updates")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue