Merge notifications by feeds

This commit is contained in:
Ash 2022-04-29 01:32:28 +08:00
parent ee5e6e3687
commit 72b07a7e0a
8 changed files with 70 additions and 46 deletions

View File

@ -562,7 +562,7 @@ interface ArticleDao {
}
@Transaction
suspend fun insertIfNotExist(articles: List<Article>): List<Article?> {
return articles.map { if (insertIfNotExist(it) > 0) it else null }
suspend fun insertIfNotExist(articles: List<Article>): List<Article> {
return articles.mapNotNull { if (insertIfNotExist(it) > 0) it else null }
}
}

View File

@ -1,14 +1,12 @@
package me.ash.reader.data.repository
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.*
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat.getSystemService
import androidx.core.app.NotificationManagerCompat
import androidx.work.CoroutineWorker
import androidx.work.ListenableWorker
import androidx.work.WorkManager
@ -25,6 +23,7 @@ import me.ash.reader.data.dao.FeedDao
import me.ash.reader.data.dao.GroupDao
import me.ash.reader.data.entity.Article
import me.ash.reader.data.entity.Feed
import me.ash.reader.data.entity.FeedWithArticle
import me.ash.reader.data.entity.Group
import me.ash.reader.data.module.DispatcherDefault
import me.ash.reader.data.module.DispatcherIO
@ -56,12 +55,9 @@ class LocalRssRepository @Inject constructor(
feedDao, rssNetworkDataSource, workManager,
dispatcherIO
) {
private val notificationManager: NotificationManager =
(getSystemService(
context,
NotificationManager::class.java
) as NotificationManager).also {
it.createNotificationChannel(
private val notificationManager: NotificationManagerCompat =
NotificationManagerCompat.from(context).apply {
createNotificationChannel(
NotificationChannel(
NotificationGroupName.ARTICLE_UPDATE,
NotificationGroupName.ARTICLE_UPDATE,
@ -105,9 +101,14 @@ class LocalRssRepository @Inject constructor(
.awaitAll()
.forEach {
if (it.isNotify) {
notify(articleDao.insertIfNotExist(it.articles))
notify(
FeedWithArticle(
it.feedWithArticle.feed,
articleDao.insertIfNotExist(it.feedWithArticle.articles)
)
)
} else {
articleDao.insertIfNotExist(it.articles)
articleDao.insertIfNotExist(it.feedWithArticle.articles)
}
}
Log.i("RlOG", "onCompletion: ${System.currentTimeMillis() - preTime}")
@ -158,7 +159,7 @@ class LocalRssRepository @Inject constructor(
}
data class ArticleNotify(
val articles: List<Article>,
val feedWithArticle: FeedWithArticle,
val isNotify: Boolean,
)
@ -170,7 +171,7 @@ class LocalRssRepository @Inject constructor(
} catch (e: Exception) {
e.printStackTrace()
Log.e("RLog", "queryRssXml[${feed.name}]: ${e.message}")
return ArticleNotify(listOf(), false)
return ArticleNotify(FeedWithArticle(feed, listOf()), false)
}
try {
// if (feed.icon == null && !articles.isNullOrEmpty()) {
@ -178,32 +179,33 @@ class LocalRssRepository @Inject constructor(
// }
} catch (e: Exception) {
Log.e("RLog", "queryRssIcon[${feed.name}]: ${e.message}")
return ArticleNotify(listOf(), false)
return ArticleNotify(FeedWithArticle(feed, listOf()), false)
}
return ArticleNotify(
articles = articles,
feedWithArticle = FeedWithArticle(feed, articles),
isNotify = articles.isNotEmpty() && feed.isNotification
)
}
private fun notify(
articles: List<Article?>,
feedWithArticle: FeedWithArticle,
) {
articles.filterNotNull().forEach { article ->
val builder = NotificationCompat.Builder(
context,
NotificationGroupName.ARTICLE_UPDATE
).setSmallIcon(R.drawable.ic_notification)
// .setLargeIcon(
// BitmapFactory.decodeResource(
// context.resources,
// R.mipmap.ic_launcher_round,
// )
// )
.setGroup(NotificationGroupName.ARTICLE_UPDATE)
notificationManager.createNotificationChannelGroup(
NotificationChannelGroup(
feedWithArticle.feed.id,
feedWithArticle.feed.name
)
)
feedWithArticle.articles.forEach { article ->
val builder = NotificationCompat.Builder(context, NotificationGroupName.ARTICLE_UPDATE)
.setSmallIcon(R.drawable.ic_notification)
.setLargeIcon(
(BitmapFactory.decodeResource(
context.resources,
R.drawable.ic_notification
))
)
.setContentTitle(article.title)
.setContentText(article.shortDescription)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(
PendingIntent.getActivity(
context,
@ -219,6 +221,13 @@ class LocalRssRepository @Inject constructor(
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
)
.setGroup(feedWithArticle.feed.id)
.setStyle(
NotificationCompat.BigTextStyle()
.bigText(article.shortDescription)
.setSummaryText(feedWithArticle.feed.name)
)
notificationManager.notify(
Random().nextInt() + article.id.hashCode(),
builder.build().apply {
@ -226,5 +235,26 @@ class LocalRssRepository @Inject constructor(
}
)
}
if (feedWithArticle.articles.size > 1) {
notificationManager.notify(
Random().nextInt() + feedWithArticle.feed.id.hashCode(),
NotificationCompat.Builder(context, NotificationGroupName.ARTICLE_UPDATE)
.setSmallIcon(R.drawable.ic_notification)
.setLargeIcon(
(BitmapFactory.decodeResource(
context.resources,
R.drawable.ic_notification
))
)
.setStyle(
NotificationCompat.InboxStyle()
.setSummaryText(feedWithArticle.feed.name)
)
.setGroup(feedWithArticle.feed.id)
.setGroupSummary(true)
.build()
)
}
}
}

View File

@ -163,7 +163,7 @@ class RssHelper @Inject constructor(
}
private fun parseDate(
inputDate: String, patterns: Array<String?> = arrayOf(
inputDate: String, patterns: Array<String> = arrayOf(
"yyyy-MM-dd'T'HH:mm:ss'Z'",
"yyyy-MM-dd",
"yyyy-MM-dd HH:mm:ss",
@ -174,7 +174,6 @@ class RssHelper @Inject constructor(
)
): Date? {
val df = SimpleDateFormat()
df.timeZone = TimeZone.getDefault()
for (pattern in patterns) {
df.applyPattern(pattern)
df.isLenient = false

View File

@ -10,8 +10,6 @@ package me.ash.reader.ui.component
import android.view.SoundEffectConstants
import androidx.compose.animation.Crossfade
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
@ -86,7 +84,7 @@ fun Banner(
)
desc?.let {
Text(
modifier = Modifier.animateContentSize(tween()),
// modifier = Modifier.animateContentSize(tween()),
text = it,
style = MaterialTheme.typography.bodyMedium,
color = (MaterialTheme.colorScheme.onSurface alwaysLight true).copy(alpha = 0.7f),

View File

@ -1,7 +1,6 @@
package me.ash.reader.ui.component
import androidx.compose.animation.*
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
@ -32,8 +31,8 @@ fun DisplayText(
) {
Text(
modifier = Modifier
.height(44.dp)
.animateContentSize(tween()),
.height(44.dp),
// .animateContentSize(tween()),
text = text,
style = MaterialTheme.typography.displaySmall.copy(
baselineShift = BaselineShift.Superscript

View File

@ -78,7 +78,7 @@ fun HomeEntry(
FlowPage(
navController = navController,
homeViewModel = homeViewModel,
pagingItems = pagingItems
pagingItems = pagingItems,
)
}
animatedComposable(route = "${RouteName.READING}/{articleId}") {

View File

@ -166,7 +166,7 @@ fun FeedsPage(
}
)
},
text = feedsViewState.account?.name ?: "",
text = feedsViewState.account?.name ?: stringResource(R.string.read_you),
desc = if (isSyncing) stringResource(R.string.syncing) else "",
)
}

View File

@ -1,6 +1,5 @@
package me.ash.reader.ui.page.home.flow
import android.util.Log
import androidx.activity.compose.BackHandler
import androidx.compose.animation.*
import androidx.compose.foundation.ExperimentalFoundationApi
@ -89,7 +88,6 @@ fun FlowPage(
LaunchedEffect(viewState.listState) {
snapshotFlow { viewState.listState.firstVisibleItemIndex }.collect {
Log.i("RLog", "FlowPage: ${it}")
if (it > 0) {
keyboardController?.hide()
}