Skip to content

Commit

Permalink
fix(greader): mark as read
Browse files Browse the repository at this point in the history
  • Loading branch information
Ashinch committed Jan 22, 2024
1 parent aff7aff commit 01f5f38
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 76 deletions.
67 changes: 64 additions & 3 deletions app/src/main/java/me/ash/reader/domain/repository/ArticleDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -562,9 +562,70 @@ interface ArticleDao {
ORDER BY date DESC
"""
)
fun queryArticleMetadataAll(
accountId: Int,
): List<ArticleMeta>
fun queryMetadataAll(accountId: Int): List<ArticleMeta>

@Transaction
@Query(
"""
SELECT id, isUnread, isStarred FROM article
WHERE accountId = :accountId
AND date < :before
ORDER BY date DESC
"""
)
fun queryMetadataAll(accountId: Int, before: Date): List<ArticleMeta>

@Transaction
@Query(
"""
SELECT id, isUnread, isStarred FROM article
WHERE accountId = :accountId
AND feedId = :feedId
ORDER BY date DESC
"""
)
fun queryMetadataByFeedId(accountId: Int, feedId: String): List<ArticleMeta>

@Transaction
@Query(
"""
SELECT id, isUnread, isStarred FROM article
WHERE accountId = :accountId
AND feedId = :feedId
AND date < :before
ORDER BY date DESC
"""
)
fun queryMetadataByFeedId(accountId: Int, feedId: String, before: Date): List<ArticleMeta>

@Transaction
@Query(
"""
SELECT a.id, a.isUnread, a.isStarred
FROM article AS a
LEFT JOIN feed AS b ON b.id = a.feedId
LEFT JOIN `group` AS c ON c.id = b.groupId
WHERE c.id = :groupId
AND a.accountId = :accountId
ORDER BY a.date DESC
"""
)
fun queryMetadataByGroupId(accountId: Int, groupId: String): List<ArticleMeta>

@Transaction
@Query(
"""
SELECT a.id, a.isUnread, a.isStarred
FROM article AS a
LEFT JOIN feed AS b ON b.id = a.feedId
LEFT JOIN `group` AS c ON c.id = b.groupId
WHERE c.id = :groupId
AND a.accountId = :accountId
AND a.date < :before
ORDER BY a.date DESC
"""
)
fun queryMetadataByGroupId(accountId: Int, groupId: String, before: Date): List<ArticleMeta>

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(vararg article: Article)
Expand Down
15 changes: 14 additions & 1 deletion app/src/main/java/me/ash/reader/domain/repository/FeedDao.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package me.ash.reader.domain.repository

import android.util.Log
import androidx.room.*
import me.ash.reader.domain.model.feed.Feed

Expand Down Expand Up @@ -91,7 +92,16 @@ interface FeedDao {
"""
SELECT * FROM feed
WHERE accountId = :accountId
and url = :url
AND (icon IS NUll OR icon = '')
"""
)
suspend fun queryNoIcon(accountId: Int): List<Feed>

@Query(
"""
SELECT * FROM feed
WHERE accountId = :accountId
AND url = :url
"""
)
suspend fun queryByLink(accountId: Int, url: String): List<Feed>
Expand All @@ -114,6 +124,9 @@ interface FeedDao {
if (feed == null) {
insert(it)
} else {
Log.i("RLog", "insertOrUpdate it: $it")
Log.i("RLog", "insertOrUpdate feed: $feed")
if (it.icon.isNullOrEmpty()) it.icon = feed.icon
// TODO: Consider migrating the fields to be nullable.
it.isNotification = feed.isNotification
it.isFullContent = feed.isFullContent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import me.ash.reader.infrastructure.preference.KeepArchivedPreference
import me.ash.reader.infrastructure.preference.SyncIntervalPreference
import me.ash.reader.infrastructure.rss.RssHelper
import me.ash.reader.ui.ext.currentAccountId
import me.ash.reader.ui.ext.decodeHTML
import me.ash.reader.ui.ext.spacerDollar
import java.util.*

Expand Down Expand Up @@ -61,7 +62,7 @@ abstract class AbstractRssRepository(
val accountId = context.currentAccountId
val feed = Feed(
id = accountId.spacerDollar(UUID.randomUUID().toString()),
name = searchedFeed.title!!,
name = searchedFeed.title.decodeHTML()!!,
url = feedLink,
groupId = groupId,
accountId = accountId,
Expand Down Expand Up @@ -166,13 +167,9 @@ abstract class AbstractRssRepository(
val latest = articleDao.queryLatestByFeedId(context.currentAccountId, feed.id)
val articles = rssHelper.queryRssXml(feed, latest?.link)
if (feed.icon == null) {
try {
val iconLink = rssHelper.queryRssIconLink(feed.url)
if (iconLink != null) {
rssHelper.saveRssIcon(feedDao, feed, iconLink)
}
} catch (e: Exception) {
Log.i("RLog", "queryRssIcon is failed: ${e.message}")
val iconLink = rssHelper.queryRssIconLink(feed.url)
if (iconLink != null) {
rssHelper.saveRssIcon(feedDao, feed, iconLink)
}
}
return FeedWithArticle(
Expand Down
19 changes: 11 additions & 8 deletions app/src/main/java/me/ash/reader/domain/service/FeverRssService.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package me.ash.reader.domain.service

import android.content.Context
import android.text.Html
import android.util.Log
import androidx.work.CoroutineWorker
import androidx.work.ListenableWorker
Expand Down Expand Up @@ -29,10 +28,7 @@ import me.ash.reader.infrastructure.di.MainDispatcher
import me.ash.reader.infrastructure.rss.RssHelper
import me.ash.reader.infrastructure.rss.provider.fever.FeverAPI
import me.ash.reader.infrastructure.rss.provider.fever.FeverDTO
import me.ash.reader.ui.ext.currentAccountId
import me.ash.reader.ui.ext.dollarLast
import me.ash.reader.ui.ext.showToast
import me.ash.reader.ui.ext.spacerDollar
import me.ash.reader.ui.ext.*
import net.dankito.readability4j.extended.Readability4JExtended
import java.util.*
import javax.inject.Inject
Expand Down Expand Up @@ -177,7 +173,7 @@ class FeverRssService @Inject constructor(
feedsBody.feeds?.map {
Feed(
id = accountId.spacerDollar(it.id!!),
name = it.title ?: context.getString(R.string.empty),
name = it.title.decodeHTML() ?: context.getString(R.string.empty),
url = it.url!!,
groupId = accountId.spacerDollar(feedsGroupsMap[it.id.toString()]!!),
accountId = accountId,
Expand All @@ -186,6 +182,13 @@ class FeverRssService @Inject constructor(
} ?: emptyList()
)

// Handle empty icon for feeds
val noIconFeeds = feedDao.queryNoIcon(accountId)
noIconFeeds.forEach {
it.icon = rssHelper.queryRssIconLink(it.url)
}
feedDao.update(*noIconFeeds.toTypedArray())

// 3. Fetch the Fever articles (up to unlimited counts)
var sinceId = account.lastArticleId?.dollarLast() ?: ""
var itemsBody = feverAPI.getItemsSince(sinceId)
Expand All @@ -195,7 +198,7 @@ class FeverRssService @Inject constructor(
Article(
id = accountId.spacerDollar(it.id!!),
date = it.created_on_time?.run { Date(this * 1000) } ?: Date(),
title = Html.fromHtml(it.title ?: context.getString(R.string.empty)).toString(),
title = it.title.decodeHTML() ?: context.getString(R.string.empty),
author = it.author,
rawDescription = it.html ?: "",
shortDescription = (Readability4JExtended("", it.html ?: "")
Expand Down Expand Up @@ -225,7 +228,7 @@ class FeverRssService @Inject constructor(
// 4. Synchronize read/unread and starred/un-starred
val unreadArticleIds = feverAPI.getUnreadItems().unread_item_ids?.split(",")
val starredArticleIds = feverAPI.getSavedItems().saved_item_ids?.split(",")
val articleMeta = articleDao.queryArticleMetadataAll(accountId)
val articleMeta = articleDao.queryMetadataAll(accountId)
for (meta: ArticleMeta in articleMeta) {
val articleId = meta.id.dollarLast()
val shouldBeUnread = unreadArticleIds?.contains(articleId)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package me.ash.reader.domain.service

import android.content.Context
import android.text.Html
import android.util.Log
import androidx.work.CoroutineWorker
import androidx.work.ListenableWorker
Expand All @@ -28,16 +27,11 @@ import me.ash.reader.infrastructure.di.IODispatcher
import me.ash.reader.infrastructure.di.MainDispatcher
import me.ash.reader.infrastructure.rss.RssHelper
import me.ash.reader.infrastructure.rss.provider.greader.GoogleReaderAPI
import me.ash.reader.infrastructure.rss.provider.greader.GoogleReaderAPI.Companion.ofCategoryIdToStreamId
import me.ash.reader.infrastructure.rss.provider.greader.GoogleReaderAPI.Companion.ofCategoryStreamIdToId
import me.ash.reader.infrastructure.rss.provider.greader.GoogleReaderAPI.Companion.ofFeedIdToStreamId
import me.ash.reader.infrastructure.rss.provider.greader.GoogleReaderAPI.Companion.ofFeedStreamIdToId
import me.ash.reader.infrastructure.rss.provider.greader.GoogleReaderAPI.Companion.ofItemStreamIdToId
import me.ash.reader.infrastructure.rss.provider.greader.GoogleReaderDTO
import me.ash.reader.ui.ext.currentAccountId
import me.ash.reader.ui.ext.dollarLast
import me.ash.reader.ui.ext.showToast
import me.ash.reader.ui.ext.spacerDollar
import me.ash.reader.ui.ext.*
import net.dankito.readability4j.extended.Readability4JExtended
import java.util.*
import javax.inject.Inject
Expand Down Expand Up @@ -216,13 +210,13 @@ class GoogleReaderRssService @Inject constructor(
val groupIds = mutableSetOf<String>()
val feedIds = mutableSetOf<String>()
val lastUpdateAt = Calendar.getInstance().apply {
if (account.updateAt != null) {
time = account.updateAt!!
add(Calendar.HOUR, -1)
} else {
// if (account.updateAt != null) {
// time = account.updateAt!!
// add(Calendar.HOUR, -1)
// } else {
time = Date()
add(Calendar.MONTH, -1)
}
// }
}.time.time / 1000

// 1. Fetch list of feeds and folders
Expand All @@ -242,21 +236,29 @@ class GoogleReaderRssService @Inject constructor(
groupIds.add(groupId)

// Handle feeds
feedDao.insert(
*feeds.map {
feedDao.insertOrUpdate(
feeds.map {
val feedId = accountId.spacerDollar(it.id?.ofFeedStreamIdToId()!!)
Feed(
id = feedId,
name = it.title ?: context.getString(R.string.empty),
name = it.title.decodeHTML() ?: context.getString(R.string.empty),
url = it.url!!,
groupId = groupId,
accountId = accountId,
icon = it.iconUrl
).also {
feedIds.add(feedId)
}
}.toTypedArray()
}
)

// Handle empty icon for feeds
val noIconFeeds = feedDao.queryNoIcon(accountId)
Log.i("RLog", "sync: $noIconFeeds")
noIconFeeds.forEach {
it.icon = rssHelper.queryRssIconLink(it.url)
}
feedDao.update(*noIconFeeds.toTypedArray())
}

// Remove orphaned groups and feeds
Expand All @@ -273,7 +275,7 @@ class GoogleReaderRssService @Inject constructor(
fetchItemsContents(unreadItems, googleReaderAPI, accountId, feedIds, unreadIds, listOf())

// 4. Fetch ids of starred items
val starredItems = googleReaderAPI.getStarredItemIds(lastUpdateAt).itemRefs
val starredItems = googleReaderAPI.getStarredItemIds().itemRefs
val starredIds = starredItems?.map { it.id }
fetchItemsContents(starredItems, googleReaderAPI, accountId, feedIds, unreadIds, starredIds)

Expand All @@ -285,7 +287,7 @@ class GoogleReaderRssService @Inject constructor(

// 7. Mark/unmark items read/starred/tagged in you app comparing
// local state and ids you've got from the GoogleReader
val articlesMeta = articleDao.queryArticleMetadataAll(accountId)
val articlesMeta = articleDao.queryMetadataAll(accountId)
for (meta: ArticleMeta in articlesMeta) {
val articleId = meta.id.dollarLast()
val shouldBeUnread = unreadIds?.contains(articleId)
Expand Down Expand Up @@ -330,7 +332,7 @@ class GoogleReaderRssService @Inject constructor(
Article(
id = accountId.spacerDollar(articleId),
date = it.published?.run { Date(this * 1000) } ?: Date(),
title = Html.fromHtml(it.title ?: context.getString(R.string.empty)).toString(),
title = it.title.decodeHTML() ?: context.getString(R.string.empty),
author = it.author,
rawDescription = it.summary?.content ?: "",
shortDescription = (Readability4JExtended("", it.summary?.content ?: "")
Expand Down Expand Up @@ -362,39 +364,42 @@ class GoogleReaderRssService @Inject constructor(
isUnread: Boolean,
) {
super.markAsRead(groupId, feedId, articleId, before, isUnread)
val accountId = context.currentAccountId
val googleReaderAPI = getGoogleReaderAPI()
val sinceTime = before?.time
when {
val markList: List<String> = when {
groupId != null -> {
googleReaderAPI.markAllAsRead(
streamId = groupId.dollarLast().ofCategoryIdToStreamId(),
sinceTimestamp = sinceTime
)
if (before == null) {
articleDao.queryMetadataByGroupId(accountId, groupId)
} else {
articleDao.queryMetadataByGroupId(accountId, groupId, before)
}.map { it.id.dollarLast() }
}

feedId != null -> {
// TODO: Nothing happened???
googleReaderAPI.markAllAsRead(
streamId = feedId.dollarLast().ofFeedIdToStreamId(),
sinceTimestamp = sinceTime
)
if (before == null) {
articleDao.queryMetadataByFeedId(accountId, feedId)
} else {
articleDao.queryMetadataByFeedId(accountId, feedId, before)
}.map { it.id.dollarLast() }
}

articleId != null -> {
googleReaderAPI.editTag(
itemIds = listOf(articleId.dollarLast()),
mark = if (!isUnread) GoogleReaderAPI.Stream.READ.tag else null,
unmark = if (isUnread) GoogleReaderAPI.Stream.READ.tag else null,
)
listOf(articleId.dollarLast())
}

else -> {
googleReaderAPI.markAllAsRead(
streamId = GoogleReaderAPI.Stream.ALL_ITEMS.tag,
sinceTimestamp = sinceTime
)
if (before == null) {
articleDao.queryMetadataAll(accountId)
} else {
articleDao.queryMetadataAll(accountId, before)
}.map { it.id.dollarLast() }
}
}
if (markList.isNotEmpty()) googleReaderAPI.editTag(
itemIds = markList,
mark = if (isUnread) null else GoogleReaderAPI.Stream.READ.tag,
unmark = if (isUnread) GoogleReaderAPI.Stream.READ.tag else null,
)
}

override suspend fun markAsStarred(articleId: String, isStarred: Boolean) {
Expand Down
Loading

0 comments on commit 01f5f38

Please sign in to comment.