Refine notification fetching

This commit is contained in:
Matthieu 2021-09-22 22:18:59 +02:00
parent 8f5e4e2317
commit df016a524f
4 changed files with 111 additions and 33 deletions

View File

@ -49,6 +49,7 @@ import org.pixeldroid.app.utils.hasInternet
import org.pixeldroid.app.utils.notificationsWorker.NotificationsWorker.Companion.INSTANCE_NOTIFICATION_TAG
import org.pixeldroid.app.utils.notificationsWorker.NotificationsWorker.Companion.SHOW_NOTIFICATION_TAG
import org.pixeldroid.app.utils.notificationsWorker.NotificationsWorker.Companion.USER_NOTIFICATION_TAG
import org.pixeldroid.app.utils.notificationsWorker.removeNotificationChannelsFromAccount
import retrofit2.HttpException
import java.io.IOException
@ -114,7 +115,7 @@ class MainActivity : BaseActivity() {
}
}
//Checks if the activity was launched from a notification from another account than the
// Checks if the activity was launched from a notification from another account than the
// current active one, and if so switches to that account
private fun notificationFromOtherUser(): Boolean {
val userOfNotification: String? = intent.extras?.getString(USER_NOTIFICATION_TAG)
@ -214,6 +215,9 @@ class MainActivity : BaseActivity() {
private fun logOut(){
finish()
removeNotificationChannelsFromAccount(applicationContext, user)
db.runInTransaction {
db.userDao().deleteActiveUsers()

View File

@ -6,6 +6,7 @@ import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
@ -25,7 +26,6 @@ import org.pixeldroid.app.utils.di.PixelfedAPIHolder
import retrofit2.HttpException
import java.io.IOException
import java.time.Instant
import java.util.*
import javax.inject.Inject
@ -48,13 +48,16 @@ class NotificationsWorker(
val users: List<UserDatabaseEntity> = db.userDao().getAll()
for (user in users){
val channelId = user.instance_uri + user.user_id
val uniqueUserId = makeChannelGroupId(user)
createNotificationChannels(
val notificationsEnabledForUser = makeNotificationChannels(
"@${user.username}@${user.instance_uri.removePrefix("https://")}",
channelId
uniqueUserId
)
//if notifications are disabled for this user, move on to next user
if(!notificationsEnabledForUser) continue
// Get newest notification from database
var previouslyLatestNotification: Notification? = db.notificationDao().latestNotification(user.user_id, user.instance_uri)
@ -81,7 +84,7 @@ class NotificationsWorker(
// Launch new notifications
filteredNewNotifications.forEach {
showNotification(it, user, channelId)
showNotification(it, user, uniqueUserId)
}
previouslyLatestNotification =
@ -105,10 +108,8 @@ class NotificationsWorker(
private fun showNotification(
notification: Notification,
user: UserDatabaseEntity,
channelIdPrefix: String
uniqueUserId: String
) {
val channelId = channelIdPrefix + (notification.type ?: "other").toString()
val intent: Intent = when (notification.type) {
mention -> notification.status?.let {
Intent(applicationContext, PostActivity::class.java).apply {
@ -128,7 +129,7 @@ class NotificationsWorker(
.putExtra(INSTANCE_NOTIFICATION_TAG, user.instance_uri)
val builder = NotificationCompat.Builder(applicationContext, channelId)
val builder = NotificationCompat.Builder(applicationContext, makeChannelId(uniqueUserId, notification.type))
.setSmallIcon(
when (notification.type) {
follow -> R.drawable.ic_follow
@ -140,6 +141,7 @@ class NotificationsWorker(
null -> R.drawable.ic_comment_empty
}
)
.setColor(Color.parseColor("#6200EE"))
.setContentTitle(
notification.account?.username?.let { username ->
applicationContext.getString(
@ -166,39 +168,59 @@ class NotificationsWorker(
builder.setContentText(notification.status?.content)
}
builder.setGroup(uniqueUserId)
with(NotificationManagerCompat.from(applicationContext)) {
// notificationId is a unique int for each notification
notify((user.instance_uri + user.user_id + notification.id).hashCode(), builder.build())
notify((uniqueUserId + notification.id).hashCode(), builder.build())
}
}
private fun createNotificationChannels(handle: String, channelId: String) {
private fun makeNotificationChannels(handle: String, channelGroupId: String): Boolean {
val notificationManager: NotificationManager =
applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// The id of the group.
val notificationManager: NotificationManager =
applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannelGroup(NotificationChannelGroup(channelId, handle))
// The id of the group, hashed (since when creating the group, it may be truncated if too long)
val hashedGroupId = channelGroupId.hashCode().toString()
notificationManager.createNotificationChannelGroup(NotificationChannelGroup(hashedGroupId, handle))
val importance = NotificationManager.IMPORTANCE_DEFAULT
val followsChannel = NotificationChannel(channelId + follow.toString(), "New followers", importance).apply { group = channelId }
val mentionChannel = NotificationChannel(channelId + mention.toString(), "Mentions", importance).apply { group = channelId }
val sharesChannel = NotificationChannel(channelId + reblog.toString(), "Shares", importance).apply { group = channelId }
val likesChannel = NotificationChannel(channelId + favourite.toString(), "Likes", importance).apply { group = channelId }
val commentsChannel = NotificationChannel(channelId + comment.toString(), "Comments", importance).apply { group = channelId }
val pollsChannel = NotificationChannel(channelId + poll.toString(), "Polls", importance).apply { group = channelId }
val othersChannel = NotificationChannel(channelId + "other", "Other", importance).apply { group = channelId }
val channels: List<NotificationChannel> = listOf(
NotificationChannel(makeChannelId(channelGroupId, follow), applicationContext.getString(R.string.followed_notification_channel), importance),
NotificationChannel(makeChannelId(channelGroupId, mention), applicationContext.getString(R.string.mention_notification_channel), importance),
NotificationChannel(makeChannelId(channelGroupId, reblog), applicationContext.getString(R.string.shared_notification_channel), importance),
NotificationChannel(makeChannelId(channelGroupId, favourite), applicationContext.getString(R.string.liked_notification_channel), importance),
NotificationChannel(makeChannelId(channelGroupId, comment), applicationContext.getString(R.string.comment_notification_channel), importance),
NotificationChannel(makeChannelId(channelGroupId, poll), applicationContext.getString(R.string.poll_notification_channel), importance),
NotificationChannel(makeChannelId(channelGroupId, null), applicationContext.getString(R.string.other_notification_channel), importance),
).map {
it.apply { group = hashedGroupId }
}
// Register the channels with the system
notificationManager.createNotificationChannel(followsChannel)
notificationManager.createNotificationChannel(mentionChannel)
notificationManager.createNotificationChannel(sharesChannel)
notificationManager.createNotificationChannel(likesChannel)
notificationManager.createNotificationChannel(commentsChannel)
notificationManager.createNotificationChannel(pollsChannel)
notificationManager.createNotificationChannel(othersChannel)
notificationManager.createNotificationChannels(channels)
//Return true if notifications are enabled, false if disabled
return notificationManager.areNotificationsEnabled() and
(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val channelGroup =
notificationManager.getNotificationChannelGroup(hashedGroupId)
!channelGroup.isBlocked
} else true) and
(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
!notificationManager.areNotificationsPaused()
} else true) and
!channels.all {
notificationManager.getNotificationChannel(it.id).importance <= NotificationManager.IMPORTANCE_NONE
}
}
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
notificationManager.areNotificationsEnabled()
} else {
true
}
}
@ -206,6 +228,39 @@ class NotificationsWorker(
const val SHOW_NOTIFICATION_TAG = "org.pixeldroid.app.SHOW_NOTIFICATION"
const val INSTANCE_NOTIFICATION_TAG = "org.pixeldroid.app.USER_NOTIFICATION"
const val USER_NOTIFICATION_TAG = "org.pixeldroid.app.INSTANCE_NOTIFICATION"
const val otherNotificationType = "other"
}
}
/**
* [channelGroupId] is the id used to uniquely identify the group: for us it is a unique id
* identifying a user consisting of the concatenation of the instance uri and user id.
*/
private fun makeChannelId(channelGroupId: String, type: Notification.NotificationType?): String =
(channelGroupId + (type ?: NotificationsWorker.otherNotificationType)).hashCode().toString()
private fun makeChannelGroupId(user: UserDatabaseEntity) = user.instance_uri + user.user_id
fun removeNotificationChannelsFromAccount(context: Context, user: UserDatabaseEntity?) = user?.let {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager: NotificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channelGroupId = makeChannelGroupId(user)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
notificationManager.deleteNotificationChannelGroup(channelGroupId.hashCode().toString())
} else {
val types: MutableList<Notification.NotificationType?> =
Notification.NotificationType.values().toMutableList()
types += null
types.forEach {
notificationManager.deleteNotificationChannel(makeChannelId(channelGroupId, it))
}
}
}
}

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/colorDrawing"
android:pathData="M7.58,4.08L6.15,2.65C3.75,4.48 2.17,7.3 2.03,10.5h2c0.15,-2.65 1.51,-4.97 3.55,-6.42zM19.97,10.5h2c-0.15,-3.2 -1.73,-6.02 -4.12,-7.85l-1.42,1.43c2.02,1.45 3.39,3.77 3.54,6.42zM18,11c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2v-5zM12,22c0.14,0 0.27,-0.01 0.4,-0.04 0.65,-0.14 1.18,-0.58 1.44,-1.18 0.1,-0.24 0.15,-0.5 0.15,-0.78h-4c0.01,1.1 0.9,2 2.01,2z"/>
</vector>

View File

@ -47,15 +47,25 @@
<!-- Notifications: like (favourite) notification -->
<string name="liked_notification">%1$s liked your post</string>
<!-- Notifications: end of poll notification -->
<string name="poll_notification">"%1$s's poll has ended"</string>
<!-- Notifications: comment notification -->
<string name="comment_notification">%1$s commented on your post</string>
<!-- Notifications: end of poll notification -->
<string name="poll_notification">"%1$s's poll has ended"</string>
<!-- Notifications: other notification -->
<string name="other_notification">"Notification from %1$s"</string>
<string name="followed_notification_channel">"New followers"</string>
<string name="mention_notification_channel">"Mentions"</string>
<string name="shared_notification_channel">"Shares"</string>
<string name="liked_notification_channel">"Likes"</string>
<string name="comment_notification_channel">"Comments"</string>
<string name="poll_notification_channel">"Polls"</string>
<string name="other_notification_channel">"Other"</string>
<!-- Login page -->
<string name="whats_an_instance">"What's an instance?"</string>
<string name="whats_an_instance_explanation">"You might be confused by the text field asking for the domain of your 'instance'.