feat: notification filtering
This commit is contained in:
parent
be97229618
commit
e1a865c973
10 changed files with 151 additions and 10 deletions
|
@ -2,6 +2,7 @@ package ani.dantotsu.connections.anilist.api
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
enum class NotificationType(val value: String) {
|
enum class NotificationType(val value: String) {
|
||||||
ACTIVITY_MESSAGE("ACTIVITY_MESSAGE"),
|
ACTIVITY_MESSAGE("ACTIVITY_MESSAGE"),
|
||||||
|
@ -24,6 +25,19 @@ enum class NotificationType(val value: String) {
|
||||||
|
|
||||||
//custom
|
//custom
|
||||||
COMMENT_REPLY("COMMENT_REPLY"),
|
COMMENT_REPLY("COMMENT_REPLY"),
|
||||||
|
COMMENT_WARNING("COMMENT_WARNING"),
|
||||||
|
DANTOTSU_UPDATE("DANTOTSU_UPDATE");
|
||||||
|
|
||||||
|
fun toFormattedString(): String {
|
||||||
|
return this.value.replace("_", " ").lowercase(Locale.ROOT)
|
||||||
|
.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.ROOT) else it.toString() }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun String.fromFormattedString(): String {
|
||||||
|
return this.replace(" ", "_").uppercase(Locale.ROOT)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
|
|
@ -64,7 +64,7 @@ class CommentNotificationTask : Task {
|
||||||
val type: CommentNotificationWorker.NotificationType = when (it.type) {
|
val type: CommentNotificationWorker.NotificationType = when (it.type) {
|
||||||
1 -> CommentNotificationWorker.NotificationType.COMMENT_REPLY
|
1 -> CommentNotificationWorker.NotificationType.COMMENT_REPLY
|
||||||
2 -> CommentNotificationWorker.NotificationType.COMMENT_WARNING
|
2 -> CommentNotificationWorker.NotificationType.COMMENT_WARNING
|
||||||
3 -> CommentNotificationWorker.NotificationType.APP_GLOBAL
|
3 -> CommentNotificationWorker.NotificationType.DANTOTSU_UPDATE
|
||||||
420 -> CommentNotificationWorker.NotificationType.NO_NOTIFICATION
|
420 -> CommentNotificationWorker.NotificationType.NO_NOTIFICATION
|
||||||
else -> CommentNotificationWorker.NotificationType.UNKNOWN
|
else -> CommentNotificationWorker.NotificationType.UNKNOWN
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,7 @@ class CommentNotificationTask : Task {
|
||||||
val commentStore = CommentStore(
|
val commentStore = CommentStore(
|
||||||
title,
|
title,
|
||||||
message,
|
message,
|
||||||
|
CommentNotificationWorker.NotificationType.COMMENT_WARNING,
|
||||||
it.mediaId,
|
it.mediaId,
|
||||||
it.commentId
|
it.commentId
|
||||||
)
|
)
|
||||||
|
@ -101,6 +102,7 @@ class CommentNotificationTask : Task {
|
||||||
val commentStore = CommentStore(
|
val commentStore = CommentStore(
|
||||||
title,
|
title,
|
||||||
message,
|
message,
|
||||||
|
CommentNotificationWorker.NotificationType.COMMENT_REPLY,
|
||||||
it.mediaId,
|
it.mediaId,
|
||||||
it.commentId
|
it.commentId
|
||||||
)
|
)
|
||||||
|
@ -118,13 +120,14 @@ class CommentNotificationTask : Task {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
CommentNotificationWorker.NotificationType.APP_GLOBAL -> {
|
CommentNotificationWorker.NotificationType.DANTOTSU_UPDATE -> {
|
||||||
val title = "Update from Dantotsu"
|
val title = "Update from Dantotsu"
|
||||||
val message = it.content ?: "New feature available"
|
val message = it.content ?: "New feature available"
|
||||||
|
|
||||||
val commentStore = CommentStore(
|
val commentStore = CommentStore(
|
||||||
title,
|
title,
|
||||||
message,
|
message,
|
||||||
|
CommentNotificationWorker.NotificationType.DANTOTSU_UPDATE,
|
||||||
null,
|
null,
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
@ -132,7 +135,7 @@ class CommentNotificationTask : Task {
|
||||||
|
|
||||||
createNotification(
|
createNotification(
|
||||||
context,
|
context,
|
||||||
CommentNotificationWorker.NotificationType.APP_GLOBAL,
|
CommentNotificationWorker.NotificationType.DANTOTSU_UPDATE,
|
||||||
message,
|
message,
|
||||||
title,
|
title,
|
||||||
0,
|
0,
|
||||||
|
@ -265,7 +268,7 @@ class CommentNotificationTask : Task {
|
||||||
builder.build()
|
builder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
CommentNotificationWorker.NotificationType.APP_GLOBAL -> {
|
CommentNotificationWorker.NotificationType.DANTOTSU_UPDATE -> {
|
||||||
val intent = Intent(context, MainActivity::class.java).apply {
|
val intent = Intent(context, MainActivity::class.java).apply {
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ class CommentNotificationWorker(appContext: Context, workerParams: WorkerParamet
|
||||||
enum class NotificationType(val id: String) {
|
enum class NotificationType(val id: String) {
|
||||||
COMMENT_REPLY(Notifications.CHANNEL_COMMENTS),
|
COMMENT_REPLY(Notifications.CHANNEL_COMMENTS),
|
||||||
COMMENT_WARNING(Notifications.CHANNEL_COMMENT_WARING),
|
COMMENT_WARNING(Notifications.CHANNEL_COMMENT_WARING),
|
||||||
APP_GLOBAL(Notifications.CHANNEL_APP_GLOBAL),
|
DANTOTSU_UPDATE(Notifications.CHANNEL_APP_GLOBAL),
|
||||||
NO_NOTIFICATION("no_notification"),
|
NO_NOTIFICATION("no_notification"),
|
||||||
UNKNOWN("unknown")
|
UNKNOWN("unknown")
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,11 @@ package ani.dantotsu.notifications.comment
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
|
||||||
@Suppress("INAPPROPRIATE_CONST_NAME")
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class CommentStore(
|
data class CommentStore(
|
||||||
val title: String,
|
val title: String,
|
||||||
val content: String,
|
val content: String,
|
||||||
|
val type: CommentNotificationWorker.NotificationType,
|
||||||
val mediaId: Int? = null,
|
val mediaId: Int? = null,
|
||||||
val commentId: Int? = null,
|
val commentId: Int? = null,
|
||||||
val time: Long = System.currentTimeMillis(),
|
val time: Long = System.currentTimeMillis(),
|
||||||
|
@ -15,6 +15,6 @@ data class CommentStore(
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@Suppress("INAPPROPRIATE_CONST_NAME")
|
@Suppress("INAPPROPRIATE_CONST_NAME")
|
||||||
private const val serialVersionUID = 1L
|
private const val serialVersionUID = 2L
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -43,6 +43,7 @@ class FollowActivity : AppCompatActivity() {
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
val layoutType = PrefManager.getVal<Int>(PrefName.FollowerLayout)
|
val layoutType = PrefManager.getVal<Int>(PrefName.FollowerLayout)
|
||||||
selected = getSelected(layoutType)
|
selected = getSelected(layoutType)
|
||||||
|
binding.followFilterButton.visibility = View.GONE
|
||||||
binding.followerGrid.alpha = 0.33f
|
binding.followerGrid.alpha = 0.33f
|
||||||
binding.followerList.alpha = 0.33f
|
binding.followerList.alpha = 0.33f
|
||||||
selected(selected)
|
selected(selected)
|
||||||
|
|
|
@ -84,6 +84,14 @@ class ActivityItemBuilder {
|
||||||
NotificationType.COMMENT_REPLY -> {
|
NotificationType.COMMENT_REPLY -> {
|
||||||
notification.context ?: "You should not see this"
|
notification.context ?: "You should not see this"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NotificationType.COMMENT_WARNING -> {
|
||||||
|
notification.context ?: "You should not see this"
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationType.DANTOTSU_UPDATE -> {
|
||||||
|
notification.context ?: "You should not see this"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,13 @@ package ani.dantotsu.profile.activity
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.CheckBox
|
||||||
|
import android.widget.ImageButton
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
@ -14,6 +19,9 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.connections.anilist.Anilist
|
import ani.dantotsu.connections.anilist.Anilist
|
||||||
import ani.dantotsu.connections.anilist.api.Notification
|
import ani.dantotsu.connections.anilist.api.Notification
|
||||||
|
import ani.dantotsu.connections.anilist.api.NotificationType
|
||||||
|
import ani.dantotsu.connections.anilist.api.NotificationType.Companion.fromFormattedString
|
||||||
|
import ani.dantotsu.currContext
|
||||||
import ani.dantotsu.databinding.ActivityFollowBinding
|
import ani.dantotsu.databinding.ActivityFollowBinding
|
||||||
import ani.dantotsu.initActivity
|
import ani.dantotsu.initActivity
|
||||||
import ani.dantotsu.media.MediaDetailsActivity
|
import ani.dantotsu.media.MediaDetailsActivity
|
||||||
|
@ -34,6 +42,7 @@ class NotificationActivity : AppCompatActivity() {
|
||||||
private lateinit var binding: ActivityFollowBinding
|
private lateinit var binding: ActivityFollowBinding
|
||||||
private var adapter: GroupieAdapter = GroupieAdapter()
|
private var adapter: GroupieAdapter = GroupieAdapter()
|
||||||
private var notificationList: List<Notification> = emptyList()
|
private var notificationList: List<Notification> = emptyList()
|
||||||
|
val filters = ArrayList<String>()
|
||||||
private var currentPage: Int = 1
|
private var currentPage: Int = 1
|
||||||
private var hasNextPage: Boolean = true
|
private var hasNextPage: Boolean = true
|
||||||
|
|
||||||
|
@ -60,6 +69,75 @@ class NotificationActivity : AppCompatActivity() {
|
||||||
onBackPressedDispatcher.onBackPressed()
|
onBackPressedDispatcher.onBackPressed()
|
||||||
}
|
}
|
||||||
binding.listProgressBar.visibility = ViewGroup.VISIBLE
|
binding.listProgressBar.visibility = ViewGroup.VISIBLE
|
||||||
|
binding.followFilterButton.setOnClickListener {
|
||||||
|
val dialogView = LayoutInflater.from(currContext()).inflate(R.layout.custom_dialog_layout, null)
|
||||||
|
val checkboxContainer = dialogView.findViewById<LinearLayout>(R.id.checkboxContainer)
|
||||||
|
val tickAllButton = dialogView.findViewById<ImageButton>(R.id.toggleButton)
|
||||||
|
fun getToggleImageResource(container: ViewGroup): Int {
|
||||||
|
var allChecked = true
|
||||||
|
var allUnchecked = true
|
||||||
|
|
||||||
|
for (i in 0 until container.childCount) {
|
||||||
|
val checkBox = container.getChildAt(i) as CheckBox
|
||||||
|
if (!checkBox.isChecked) {
|
||||||
|
allChecked = false
|
||||||
|
} else {
|
||||||
|
allUnchecked = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return when {
|
||||||
|
allChecked -> R.drawable.untick_all_boxes
|
||||||
|
allUnchecked -> R.drawable.tick_all_boxes
|
||||||
|
else -> R.drawable.invert_all_boxes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NotificationType.entries.forEach { notificationType ->
|
||||||
|
val checkBox = CheckBox(currContext())
|
||||||
|
checkBox.text = notificationType.toFormattedString()
|
||||||
|
checkBox.isChecked = !filters.contains(notificationType.value.fromFormattedString())
|
||||||
|
checkBox.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
if (isChecked) {
|
||||||
|
filters.remove(notificationType.value.fromFormattedString())
|
||||||
|
} else {
|
||||||
|
filters.add(notificationType.value.fromFormattedString())
|
||||||
|
}
|
||||||
|
tickAllButton.setImageResource(getToggleImageResource(checkboxContainer))
|
||||||
|
}
|
||||||
|
checkboxContainer.addView(checkBox)
|
||||||
|
}
|
||||||
|
tickAllButton.setImageResource(getToggleImageResource(checkboxContainer))
|
||||||
|
tickAllButton.setOnClickListener {
|
||||||
|
for (i in 0 until checkboxContainer.childCount) {
|
||||||
|
val checkBox = checkboxContainer.getChildAt(i) as CheckBox
|
||||||
|
checkBox.isChecked = !checkBox.isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
tickAllButton.setImageResource(getToggleImageResource(checkboxContainer))
|
||||||
|
}
|
||||||
|
val alertD = AlertDialog.Builder(this, R.style.MyPopup)
|
||||||
|
alertD.setTitle("Filter")
|
||||||
|
alertD.setView(dialogView)
|
||||||
|
alertD.setPositiveButton("OK") { _, _ ->
|
||||||
|
currentPage = 1
|
||||||
|
hasNextPage = true
|
||||||
|
adapter.clear()
|
||||||
|
adapter.addAll(notificationList.filter { notification ->
|
||||||
|
!filters.contains(notification.notificationType)
|
||||||
|
}.map {
|
||||||
|
NotificationItem(
|
||||||
|
it,
|
||||||
|
::onNotificationClick
|
||||||
|
)
|
||||||
|
})
|
||||||
|
loadPage(-1) {
|
||||||
|
binding.followRefresh.visibility = ViewGroup.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alertD.setNegativeButton("Cancel") { _, _ -> }
|
||||||
|
val dialog = alertD.show()
|
||||||
|
dialog.window?.setDimAmount(0.8f)
|
||||||
|
}
|
||||||
|
|
||||||
val activityId = intent.getIntExtra("activityId", -1)
|
val activityId = intent.getIntExtra("activityId", -1)
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
loadPage(activityId) {
|
loadPage(activityId) {
|
||||||
|
@ -119,10 +197,10 @@ class NotificationActivity : AppCompatActivity() {
|
||||||
) ?: listOf()
|
) ?: listOf()
|
||||||
commentStore.forEach {
|
commentStore.forEach {
|
||||||
val notification = Notification(
|
val notification = Notification(
|
||||||
"COMMENT_REPLY",
|
it.type.toString(),
|
||||||
System.currentTimeMillis().toInt(),
|
System.currentTimeMillis().toInt(),
|
||||||
commentId = it.commentId,
|
commentId = it.commentId,
|
||||||
notificationType = "COMMENT_REPLY",
|
notificationType = it.type.toString(),
|
||||||
mediaId = it.mediaId,
|
mediaId = it.mediaId,
|
||||||
context = it.title + "\n" + it.content,
|
context = it.title + "\n" + it.content,
|
||||||
createdAt = (it.time / 1000L).toInt(),
|
createdAt = (it.time / 1000L).toInt(),
|
||||||
|
@ -133,7 +211,9 @@ class NotificationActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationList += newNotifications
|
notificationList += newNotifications
|
||||||
adapter.addAll(newNotifications.map {
|
adapter.addAll(newNotifications.filter { notification ->
|
||||||
|
!filters.contains(notification.notificationType)
|
||||||
|
}.map {
|
||||||
NotificationItem(
|
NotificationItem(
|
||||||
it,
|
it,
|
||||||
::onNotificationClick
|
::onNotificationClick
|
||||||
|
|
|
@ -315,6 +315,23 @@ class NotificationItem(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NotificationType.COMMENT_WARNING -> {
|
||||||
|
image(user = true, commentNotification = true)
|
||||||
|
if (notification.commentId != null && notification.mediaId != null) {
|
||||||
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
|
clickCallback(
|
||||||
|
notification.mediaId,
|
||||||
|
notification.commentId,
|
||||||
|
NotificationClickType.COMMENT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationType.DANTOTSU_UPDATE -> {
|
||||||
|
image(user = true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -397,6 +397,14 @@ object PrefManager {
|
||||||
} else {
|
} else {
|
||||||
default
|
default
|
||||||
}
|
}
|
||||||
|
} catch (e: java.io.InvalidClassException) {
|
||||||
|
try {
|
||||||
|
getPrefLocation(location).edit().remove(key).apply()
|
||||||
|
default
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Logger.log(e)
|
||||||
|
default
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Logger.log(e)
|
Logger.log(e)
|
||||||
default
|
default
|
||||||
|
|
|
@ -50,6 +50,16 @@
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
tools:text="Follow" />
|
tools:text="Follow" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/followFilterButton"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_gravity="end|center_vertical"
|
||||||
|
android:contentDescription="@string/menu"
|
||||||
|
android:src="@drawable/ic_round_filter_alt_24"
|
||||||
|
app:tint="?attr/colorOnBackground" />
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
<androidx.cardview.widget.CardView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue