feat: notification filtering

This commit is contained in:
rebelonion 2024-05-09 06:02:17 -05:00
parent be97229618
commit e1a865c973
10 changed files with 151 additions and 10 deletions

View file

@ -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

View file

@ -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
} }

View file

@ -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")
} }

View file

@ -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
} }
} }

View file

@ -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)

View file

@ -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"
}
} }
} }

View file

@ -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

View file

@ -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)
}
} }
} }

View file

@ -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

View file

@ -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"