From 72b07a7e0a532216de502c0ddf425237b4afa2c4 Mon Sep 17 00:00:00 2001 From: Ash Date: Fri, 29 Apr 2022 01:32:28 +0800 Subject: [PATCH] Merge notifications by feeds --- .../java/me/ash/reader/data/dao/ArticleDao.kt | 4 +- .../data/repository/LocalRssRepository.kt | 94 ++++++++++++------- .../ash/reader/data/repository/RssHelper.kt | 3 +- .../java/me/ash/reader/ui/component/Banner.kt | 4 +- .../me/ash/reader/ui/component/DisplayText.kt | 5 +- .../me/ash/reader/ui/page/common/HomeEntry.kt | 2 +- .../reader/ui/page/home/feeds/FeedsPage.kt | 2 +- .../ash/reader/ui/page/home/flow/FlowPage.kt | 2 - 8 files changed, 70 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/me/ash/reader/data/dao/ArticleDao.kt b/app/src/main/java/me/ash/reader/data/dao/ArticleDao.kt index 2e50cbc..26c742c 100644 --- a/app/src/main/java/me/ash/reader/data/dao/ArticleDao.kt +++ b/app/src/main/java/me/ash/reader/data/dao/ArticleDao.kt @@ -562,7 +562,7 @@ interface ArticleDao { } @Transaction - suspend fun insertIfNotExist(articles: List
): List { - return articles.map { if (insertIfNotExist(it) > 0) it else null } + suspend fun insertIfNotExist(articles: List
): List
{ + return articles.mapNotNull { if (insertIfNotExist(it) > 0) it else null } } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/repository/LocalRssRepository.kt b/app/src/main/java/me/ash/reader/data/repository/LocalRssRepository.kt index 8a9834d..d0e2aee 100644 --- a/app/src/main/java/me/ash/reader/data/repository/LocalRssRepository.kt +++ b/app/src/main/java/me/ash/reader/data/repository/LocalRssRepository.kt @@ -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
, + 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, + 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() + ) + } } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/repository/RssHelper.kt b/app/src/main/java/me/ash/reader/data/repository/RssHelper.kt index 561343b..9fdfae9 100644 --- a/app/src/main/java/me/ash/reader/data/repository/RssHelper.kt +++ b/app/src/main/java/me/ash/reader/data/repository/RssHelper.kt @@ -163,7 +163,7 @@ class RssHelper @Inject constructor( } private fun parseDate( - inputDate: String, patterns: Array = arrayOf( + inputDate: String, patterns: Array = 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 diff --git a/app/src/main/java/me/ash/reader/ui/component/Banner.kt b/app/src/main/java/me/ash/reader/ui/component/Banner.kt index aafbc18..f00e857 100644 --- a/app/src/main/java/me/ash/reader/ui/component/Banner.kt +++ b/app/src/main/java/me/ash/reader/ui/component/Banner.kt @@ -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), diff --git a/app/src/main/java/me/ash/reader/ui/component/DisplayText.kt b/app/src/main/java/me/ash/reader/ui/component/DisplayText.kt index 2c0bc8f..a2fffee 100644 --- a/app/src/main/java/me/ash/reader/ui/component/DisplayText.kt +++ b/app/src/main/java/me/ash/reader/ui/component/DisplayText.kt @@ -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 diff --git a/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt b/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt index 378d1ea..df74516 100644 --- a/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt +++ b/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt @@ -78,7 +78,7 @@ fun HomeEntry( FlowPage( navController = navController, homeViewModel = homeViewModel, - pagingItems = pagingItems + pagingItems = pagingItems, ) } animatedComposable(route = "${RouteName.READING}/{articleId}") { diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt index 0473c38..e38b36f 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt @@ -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 "", ) } diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt index 52074c8..4dce242 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt @@ -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() }