mirror of https://github.com/Ashinch/ReadYou.git
fix(greader): mark all as read (#582)
This commit is contained in:
parent
f14aecb2a9
commit
9327a2734f
|
@ -286,11 +286,13 @@ interface ArticleDao {
|
|||
before: Date,
|
||||
)
|
||||
|
||||
@Transaction
|
||||
@Query(
|
||||
"""
|
||||
UPDATE article SET isUnread = :isUnread
|
||||
WHERE accountId = :accountId
|
||||
AND date < :before
|
||||
AND isUnread != :isUnread
|
||||
"""
|
||||
)
|
||||
suspend fun markAllAsRead(
|
||||
|
@ -299,6 +301,7 @@ interface ArticleDao {
|
|||
before: Date,
|
||||
)
|
||||
|
||||
@Transaction
|
||||
@Query(
|
||||
"""
|
||||
UPDATE article SET isUnread = :isUnread
|
||||
|
@ -307,6 +310,7 @@ interface ArticleDao {
|
|||
WHERE groupId = :groupId
|
||||
)
|
||||
AND accountId = :accountId
|
||||
AND isUnread != :isUnread
|
||||
AND date < :before
|
||||
"""
|
||||
)
|
||||
|
@ -317,11 +321,13 @@ interface ArticleDao {
|
|||
before: Date,
|
||||
)
|
||||
|
||||
@Transaction
|
||||
@Query(
|
||||
"""
|
||||
UPDATE article SET isUnread = :isUnread
|
||||
WHERE feedId = :feedId
|
||||
AND accountId = :accountId
|
||||
AND isUnread != :isUnread
|
||||
AND date < :before
|
||||
"""
|
||||
)
|
||||
|
@ -332,6 +338,7 @@ interface ArticleDao {
|
|||
before: Date,
|
||||
)
|
||||
|
||||
@Transaction
|
||||
@Query(
|
||||
"""
|
||||
UPDATE article SET isUnread = :isUnread
|
||||
|
@ -632,6 +639,17 @@ interface ArticleDao {
|
|||
)
|
||||
fun queryMetadataAll(accountId: Int): List<ArticleMeta>
|
||||
|
||||
@Transaction
|
||||
@Query(
|
||||
"""
|
||||
SELECT id, isUnread, isStarred FROM article
|
||||
WHERE accountId = :accountId
|
||||
AND isUnread = :isUnread
|
||||
ORDER BY date DESC
|
||||
"""
|
||||
)
|
||||
fun queryMetadataAll(accountId: Int, isUnread: Boolean): List<ArticleMeta>
|
||||
|
||||
@Transaction
|
||||
@Query(
|
||||
"""
|
||||
|
@ -648,11 +666,12 @@ interface ArticleDao {
|
|||
"""
|
||||
SELECT id, isUnread, isStarred FROM article
|
||||
WHERE accountId = :accountId
|
||||
AND feedId = :feedId
|
||||
AND isUnread = :isUnread
|
||||
AND date < :before
|
||||
ORDER BY date DESC
|
||||
"""
|
||||
)
|
||||
fun queryMetadataByFeedId(accountId: Int, feedId: String): List<ArticleMeta>
|
||||
fun queryMetadataAll(accountId: Int, isUnread: Boolean, before: Date): List<ArticleMeta>
|
||||
|
||||
@Transaction
|
||||
@Query(
|
||||
|
@ -660,11 +679,24 @@ interface ArticleDao {
|
|||
SELECT id, isUnread, isStarred FROM article
|
||||
WHERE accountId = :accountId
|
||||
AND feedId = :feedId
|
||||
AND isUnread = :isUnread
|
||||
ORDER BY date DESC
|
||||
"""
|
||||
)
|
||||
fun queryMetadataByFeedId(accountId: Int, feedId: String, isUnread: Boolean): List<ArticleMeta>
|
||||
|
||||
@Transaction
|
||||
@Query(
|
||||
"""
|
||||
SELECT id, isUnread, isStarred FROM article
|
||||
WHERE accountId = :accountId
|
||||
AND feedId = :feedId
|
||||
AND isUnread = :isUnread
|
||||
AND date < :before
|
||||
ORDER BY date DESC
|
||||
"""
|
||||
)
|
||||
fun queryMetadataByFeedId(accountId: Int, feedId: String, before: Date): List<ArticleMeta>
|
||||
fun queryMetadataByFeedId(accountId: Int, feedId: String, isUnread: Boolean, before: Date): List<ArticleMeta>
|
||||
|
||||
@Transaction
|
||||
@Query(
|
||||
|
@ -675,10 +707,11 @@ interface ArticleDao {
|
|||
LEFT JOIN `group` AS c ON c.id = b.groupId
|
||||
WHERE c.id = :groupId
|
||||
AND a.accountId = :accountId
|
||||
AND a.isUnread = :isUnread
|
||||
ORDER BY a.date DESC
|
||||
"""
|
||||
)
|
||||
fun queryMetadataByGroupId(accountId: Int, groupId: String): List<ArticleMeta>
|
||||
fun queryMetadataByGroupIdWhenIsUnread(accountId: Int, groupId: String, isUnread: Boolean): List<ArticleMeta>
|
||||
|
||||
@Transaction
|
||||
@Query(
|
||||
|
@ -689,11 +722,12 @@ interface ArticleDao {
|
|||
LEFT JOIN `group` AS c ON c.id = b.groupId
|
||||
WHERE c.id = :groupId
|
||||
AND a.accountId = :accountId
|
||||
AND a.isUnread = :isUnread
|
||||
AND a.date < :before
|
||||
ORDER BY a.date DESC
|
||||
"""
|
||||
)
|
||||
fun queryMetadataByGroupId(accountId: Int, groupId: String, before: Date): List<ArticleMeta>
|
||||
fun queryMetadataByGroupIdWhenIsUnread(accountId: Int, groupId: String, isUnread: Boolean, before: Date): List<ArticleMeta>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insert(vararg article: Article)
|
||||
|
|
|
@ -140,7 +140,7 @@ abstract class AbstractRssRepository(
|
|||
)
|
||||
}
|
||||
|
||||
feedId != null && articleId == null -> {
|
||||
feedId != null -> {
|
||||
articleDao.markAllAsReadByFeedId(
|
||||
accountId = accountId,
|
||||
feedId = feedId,
|
||||
|
|
|
@ -184,16 +184,16 @@ class GoogleReaderRssService @Inject constructor(
|
|||
}
|
||||
|
||||
/**
|
||||
* This is a reference to Reeder's synchronization logic,
|
||||
* This is improved from Reeder's synchronization strategy,
|
||||
* which syncs well across multiple devices.
|
||||
*
|
||||
* 1. Fetch tags (not supported yet)
|
||||
* 2. Fetch folder and subscription list
|
||||
* 3. Fetch all unread item id list
|
||||
* 4. Fetch all starred item id list
|
||||
* 5. Fetch unread contents of items with differences
|
||||
* 5. Fetch unread contents of items with differences (up to 10k items per sync process)
|
||||
* 6. Fetch starred contents of items with differences
|
||||
* 7. Fetch read contents of items with differences
|
||||
* 7. Fetch read contents of items with differences (up to one month old)
|
||||
* 8. Remove orphaned groups and feeds, after synchronizing the starred/un-starred
|
||||
*
|
||||
* The following link contains other great synchronization logic,
|
||||
|
@ -277,16 +277,16 @@ class GoogleReaderRssService @Inject constructor(
|
|||
googleReaderAPI.getUnreadItemIds(continuationId = it)
|
||||
}.toSet()
|
||||
Log.i("RLog", "sync unreadIds size: ${unreadIds.size}")
|
||||
val toBeUnread = unreadIds - localUnreadIds
|
||||
val toBeUnread = (unreadIds - localUnreadIds).run {
|
||||
if (size > 10000) take(10000).toSet() else this
|
||||
}
|
||||
Log.i("RLog", "sync toBeUnread size: ${toBeUnread.size}")
|
||||
if (toBeUnread.isNotEmpty()) {
|
||||
toBeUnread.chunked(999).forEach {
|
||||
articleDao.markAsReadByIdSet(
|
||||
accountId = accountId,
|
||||
ids = it.toSet(),
|
||||
isUnread = true,
|
||||
)
|
||||
}
|
||||
toBeUnread.takeIf { it.isNotEmpty() }?.chunked(500)?.forEach {
|
||||
articleDao.markAsReadByIdSet(
|
||||
accountId = accountId,
|
||||
ids = it.toSet(),
|
||||
isUnread = true,
|
||||
)
|
||||
}
|
||||
|
||||
// 4. Fetch all starred item id list
|
||||
|
@ -296,17 +296,15 @@ class GoogleReaderRssService @Inject constructor(
|
|||
Log.i("RLog", "sync starredIds size: ${starredIds.size}")
|
||||
val toBeStarred = starredIds - localStarredIds
|
||||
Log.i("RLog", "sync toBeStarred size: ${toBeStarred.size}")
|
||||
if (toBeStarred.isNotEmpty()) {
|
||||
toBeStarred.chunked(999).forEach {
|
||||
articleDao.markAsStarredByIdSet(
|
||||
accountId = accountId,
|
||||
ids = it.toSet(),
|
||||
isStarred = true,
|
||||
)
|
||||
}
|
||||
toBeStarred.takeIf { it.isNotEmpty() }?.chunked(500)?.forEach {
|
||||
articleDao.markAsStarredByIdSet(
|
||||
accountId = accountId,
|
||||
ids = it.toSet(),
|
||||
isStarred = true,
|
||||
)
|
||||
}
|
||||
|
||||
// 5. Fetch unread contents of items with differences
|
||||
// 5. Fetch unread contents of items with differences (up to 10k items per sync process)
|
||||
fetchItemsContents(
|
||||
itemIds = toBeUnread,
|
||||
googleReaderAPI = googleReaderAPI,
|
||||
|
@ -328,14 +326,14 @@ class GoogleReaderRssService @Inject constructor(
|
|||
preDate = preDate,
|
||||
)
|
||||
|
||||
// 7. Fetch read contents of items with differences
|
||||
// 7. Fetch read contents of items with differences (up to one month old)
|
||||
val readIds = fetchItemIdsAndContinue {
|
||||
googleReaderAPI.getReadItemIds(since = lastMonthAt, continuationId = it)
|
||||
}.toSet()
|
||||
Log.i("RLog", "sync readIds size: ${readIds.size}")
|
||||
val localReadIds = articleDao.queryMetadataAll(accountId).filter { !it.isUnread }
|
||||
.map { it.id.dollarLast() }.toSet()
|
||||
val toBeRead = readIds - unreadIds - localReadIds
|
||||
var toBeRead = readIds - unreadIds - localReadIds
|
||||
Log.i("RLog", "sync toBeRead size: ${toBeRead.size}")
|
||||
if (toBeRead.isNotEmpty()) {
|
||||
fetchItemsContents(
|
||||
|
@ -348,6 +346,16 @@ class GoogleReaderRssService @Inject constructor(
|
|||
preDate = preDate,
|
||||
)
|
||||
}
|
||||
// Sync the read status of articles prior to last month
|
||||
toBeRead = localUnreadIds - unreadIds
|
||||
Log.i("RLog", "sync toBeRead (last month) size: ${toBeRead.size}")
|
||||
toBeRead.takeIf { it.isNotEmpty() }?.chunked(500)?.forEach {
|
||||
articleDao.markAsReadByIdSet(
|
||||
accountId = accountId,
|
||||
ids = it.toSet(),
|
||||
isUnread = false,
|
||||
)
|
||||
}
|
||||
|
||||
// 8. Remove orphaned groups and feeds, after synchronizing the starred/un-starred
|
||||
groupDao.queryAll(accountId)
|
||||
|
@ -428,23 +436,25 @@ class GoogleReaderRssService @Inject constructor(
|
|||
before: Date?,
|
||||
isUnread: Boolean,
|
||||
) {
|
||||
super.markAsRead(groupId, feedId, articleId, before, isUnread)
|
||||
val accountId = context.currentAccountId
|
||||
val googleReaderAPI = getGoogleReaderAPI()
|
||||
val markList: List<String> = when {
|
||||
groupId != null -> {
|
||||
if (before == null) {
|
||||
articleDao.queryMetadataByGroupId(accountId, groupId)
|
||||
articleDao.queryMetadataByGroupIdWhenIsUnread(accountId, groupId, !isUnread)
|
||||
} else {
|
||||
articleDao.queryMetadataByGroupId(accountId, groupId, before)
|
||||
articleDao.queryMetadataByGroupIdWhenIsUnread(accountId,
|
||||
groupId,
|
||||
!isUnread,
|
||||
before)
|
||||
}.map { it.id.dollarLast() }
|
||||
}
|
||||
|
||||
feedId != null -> {
|
||||
if (before == null) {
|
||||
articleDao.queryMetadataByFeedId(accountId, feedId)
|
||||
articleDao.queryMetadataByFeedId(accountId, feedId, !isUnread)
|
||||
} else {
|
||||
articleDao.queryMetadataByFeedId(accountId, feedId, before)
|
||||
articleDao.queryMetadataByFeedId(accountId, feedId, !isUnread, before)
|
||||
}.map { it.id.dollarLast() }
|
||||
}
|
||||
|
||||
|
@ -454,17 +464,21 @@ class GoogleReaderRssService @Inject constructor(
|
|||
|
||||
else -> {
|
||||
if (before == null) {
|
||||
articleDao.queryMetadataAll(accountId)
|
||||
articleDao.queryMetadataAll(accountId, !isUnread)
|
||||
} else {
|
||||
articleDao.queryMetadataAll(accountId, before)
|
||||
articleDao.queryMetadataAll(accountId, !isUnread, before)
|
||||
}.map { it.id.dollarLast() }
|
||||
}
|
||||
}
|
||||
if (markList.isNotEmpty()) googleReaderAPI.editTag(
|
||||
itemIds = markList,
|
||||
mark = if (!isUnread) GoogleReaderAPI.Stream.READ.tag else null,
|
||||
unmark = if (isUnread) GoogleReaderAPI.Stream.READ.tag else null,
|
||||
)
|
||||
super.markAsRead(groupId, feedId, articleId, before, isUnread)
|
||||
markList.takeIf { it.isNotEmpty() }?.chunked(500)?.forEach {
|
||||
Log.d("RLog", "sync markAsRead: ${it.size} num")
|
||||
googleReaderAPI.editTag(
|
||||
itemIds = it,
|
||||
mark = if (!isUnread) GoogleReaderAPI.Stream.READ.tag else null,
|
||||
unmark = if (isUnread) GoogleReaderAPI.Stream.READ.tag else null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun markAsStarred(articleId: String, isStarred: Boolean) {
|
||||
|
|
|
@ -256,7 +256,7 @@ class GoogleReaderAPI private constructor(
|
|||
retryablePostRequest<String>(
|
||||
query = "reader/api/0/edit-tag",
|
||||
form = mutableListOf<Pair<String, String>>().apply {
|
||||
itemIds.forEach { add(Pair("i", it.ofItemIdToStreamId())) }
|
||||
itemIds.forEach { add(Pair("i", it.ofItemIdToHexId())) }
|
||||
mark?.let { add(Pair("a", mark)) }
|
||||
unmark?.let { add(Pair("r", unmark)) }
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package me.ash.reader.ui.page.home
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
|
@ -10,7 +9,13 @@ import androidx.work.WorkManager
|
|||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.domain.model.article.ArticleFlowItem
|
||||
import me.ash.reader.domain.model.article.mapPagingFlowItem
|
||||
|
@ -18,8 +23,8 @@ import me.ash.reader.domain.model.feed.Feed
|
|||
import me.ash.reader.domain.model.general.Filter
|
||||
import me.ash.reader.domain.model.group.Group
|
||||
import me.ash.reader.domain.service.RssService
|
||||
import me.ash.reader.infrastructure.android.AndroidStringsHelper
|
||||
import me.ash.reader.domain.service.SyncWorker
|
||||
import me.ash.reader.infrastructure.android.AndroidStringsHelper
|
||||
import me.ash.reader.infrastructure.di.ApplicationScope
|
||||
import me.ash.reader.infrastructure.di.IODispatcher
|
||||
import javax.inject.Inject
|
||||
|
@ -44,7 +49,7 @@ class HomeViewModel @Inject constructor(
|
|||
val syncWorkLiveData = workManager.getWorkInfosByTagLiveData(SyncWorker.WORK_NAME)
|
||||
|
||||
fun sync() {
|
||||
viewModelScope.launch(ioDispatcher) {
|
||||
applicationScope.launch(ioDispatcher) {
|
||||
rssService.get().doSync()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import kotlinx.coroutines.withContext
|
|||
import me.ash.reader.domain.model.feed.Feed
|
||||
import me.ash.reader.domain.model.group.Group
|
||||
import me.ash.reader.domain.service.RssService
|
||||
import me.ash.reader.infrastructure.di.ApplicationScope
|
||||
import me.ash.reader.infrastructure.di.IODispatcher
|
||||
import me.ash.reader.infrastructure.di.MainDispatcher
|
||||
import javax.inject.Inject
|
||||
|
@ -29,6 +30,8 @@ class FeedOptionViewModel @Inject constructor(
|
|||
private val mainDispatcher: CoroutineDispatcher,
|
||||
@IODispatcher
|
||||
private val ioDispatcher: CoroutineDispatcher,
|
||||
@ApplicationScope
|
||||
private val applicationScope: CoroutineScope,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _feedOptionUiState = MutableStateFlow(FeedOptionUiState())
|
||||
|
@ -87,7 +90,7 @@ class FeedOptionViewModel @Inject constructor(
|
|||
|
||||
fun addNewGroup() {
|
||||
if (_feedOptionUiState.value.newGroupContent.isNotBlank()) {
|
||||
viewModelScope.launch {
|
||||
applicationScope.launch {
|
||||
selectedGroup(rssService.get().addGroup(
|
||||
destFeed = _feedOptionUiState.value.feed,
|
||||
newGroupName = _feedOptionUiState.value.newGroupContent))
|
||||
|
@ -97,7 +100,7 @@ class FeedOptionViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun selectedGroup(groupId: String) {
|
||||
viewModelScope.launch(ioDispatcher) {
|
||||
applicationScope.launch(ioDispatcher) {
|
||||
_feedOptionUiState.value.feed?.let {
|
||||
rssService.get().moveFeed(
|
||||
originGroupId = it.groupId,
|
||||
|
@ -128,7 +131,7 @@ class FeedOptionViewModel @Inject constructor(
|
|||
|
||||
fun delete(callback: () -> Unit = {}) {
|
||||
_feedOptionUiState.value.feed?.let {
|
||||
viewModelScope.launch(ioDispatcher) {
|
||||
applicationScope.launch(ioDispatcher) {
|
||||
rssService.get().deleteFeed(it)
|
||||
withContext(mainDispatcher) {
|
||||
callback()
|
||||
|
@ -166,7 +169,7 @@ class FeedOptionViewModel @Inject constructor(
|
|||
|
||||
fun renameFeed() {
|
||||
_feedOptionUiState.value.feed?.let {
|
||||
viewModelScope.launch {
|
||||
applicationScope.launch {
|
||||
rssService.get().renameFeed(it.copy(name = _feedOptionUiState.value.newName))
|
||||
_feedOptionUiState.update { it.copy(renameDialogVisible = false) }
|
||||
}
|
||||
|
@ -219,7 +222,7 @@ class FeedOptionViewModel @Inject constructor(
|
|||
|
||||
fun changeFeedUrl() {
|
||||
_feedOptionUiState.value.feed?.let {
|
||||
viewModelScope.launch {
|
||||
applicationScope.launch {
|
||||
rssService.get().changeFeedUrl(it.copy(url = _feedOptionUiState.value.newUrl))
|
||||
_feedOptionUiState.update { it.copy(changeUrlDialogVisible = false) }
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.withContext
|
||||
import me.ash.reader.domain.model.group.Group
|
||||
import me.ash.reader.domain.service.RssService
|
||||
import me.ash.reader.infrastructure.di.ApplicationScope
|
||||
import me.ash.reader.infrastructure.di.IODispatcher
|
||||
import me.ash.reader.infrastructure.di.MainDispatcher
|
||||
import javax.inject.Inject
|
||||
|
@ -28,6 +29,8 @@ class GroupOptionViewModel @Inject constructor(
|
|||
private val mainDispatcher: CoroutineDispatcher,
|
||||
@IODispatcher
|
||||
private val ioDispatcher: CoroutineDispatcher,
|
||||
@ApplicationScope
|
||||
private val applicationScope: CoroutineScope,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _groupOptionUiState = MutableStateFlow(GroupOptionUiState())
|
||||
|
@ -92,7 +95,7 @@ class GroupOptionViewModel @Inject constructor(
|
|||
|
||||
fun delete(callback: () -> Unit = {}) {
|
||||
_groupOptionUiState.value.group?.let {
|
||||
viewModelScope.launch(ioDispatcher) {
|
||||
applicationScope.launch(ioDispatcher) {
|
||||
rssService.get().deleteGroup(it)
|
||||
withContext(mainDispatcher) {
|
||||
callback()
|
||||
|
@ -161,7 +164,7 @@ class GroupOptionViewModel @Inject constructor(
|
|||
|
||||
fun rename() {
|
||||
_groupOptionUiState.value.group?.let {
|
||||
viewModelScope.launch {
|
||||
applicationScope.launch {
|
||||
rssService.get().renameGroup(it.copy(name = _groupOptionUiState.value.newName))
|
||||
_groupOptionUiState.update { it.copy(renameDialogVisible = false) }
|
||||
}
|
||||
|
|
|
@ -5,14 +5,21 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.rometools.rome.feed.synd.SyndFeed
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.domain.model.group.Group
|
||||
import me.ash.reader.domain.service.OpmlService
|
||||
import me.ash.reader.domain.service.RssService
|
||||
import me.ash.reader.infrastructure.android.AndroidStringsHelper
|
||||
import me.ash.reader.infrastructure.di.ApplicationScope
|
||||
import me.ash.reader.infrastructure.rss.RssHelper
|
||||
import me.ash.reader.ui.ext.formatUrl
|
||||
import java.io.InputStream
|
||||
|
@ -24,6 +31,8 @@ class SubscribeViewModel @Inject constructor(
|
|||
val rssService: RssService,
|
||||
private val rssHelper: RssHelper,
|
||||
private val androidStringsHelper: AndroidStringsHelper,
|
||||
@ApplicationScope
|
||||
private val applicationScope: CoroutineScope,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _subscribeUiState = MutableStateFlow(SubscribeUiState())
|
||||
|
@ -48,7 +57,7 @@ class SubscribeViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun importFromInputStream(inputStream: InputStream) {
|
||||
viewModelScope.launch {
|
||||
applicationScope.launch {
|
||||
try {
|
||||
opmlService.saveToDatabase(inputStream)
|
||||
rssService.get().doSync()
|
||||
|
@ -64,7 +73,7 @@ class SubscribeViewModel @Inject constructor(
|
|||
|
||||
fun addNewGroup() {
|
||||
if (_subscribeUiState.value.newGroupContent.isNotBlank()) {
|
||||
viewModelScope.launch {
|
||||
applicationScope.launch {
|
||||
// TODO: How to add a single group without no feeds via Google Reader API?
|
||||
selectedGroup(rssService.get().addGroup(null, _subscribeUiState.value.newGroupContent))
|
||||
hideNewGroupDialog()
|
||||
|
@ -141,7 +150,7 @@ class SubscribeViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun subscribe() {
|
||||
viewModelScope.launch {
|
||||
applicationScope.launch {
|
||||
rssService.get().subscribe(
|
||||
searchedFeed = _subscribeUiState.value.searchedFeed ?: return@launch,
|
||||
feedLink = _subscribeUiState.value.linkContent,
|
||||
|
|
|
@ -2,15 +2,16 @@ package me.ash.reader.ui.page.home.flow
|
|||
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.domain.model.general.MarkAsReadConditions
|
||||
import me.ash.reader.domain.service.RssService
|
||||
import me.ash.reader.infrastructure.di.ApplicationScope
|
||||
import me.ash.reader.infrastructure.di.IODispatcher
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -19,13 +20,15 @@ class FlowViewModel @Inject constructor(
|
|||
private val rssService: RssService,
|
||||
@IODispatcher
|
||||
private val ioDispatcher: CoroutineDispatcher,
|
||||
@ApplicationScope
|
||||
private val applicationScope: CoroutineScope,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _flowUiState = MutableStateFlow(FlowUiState())
|
||||
val flowUiState: StateFlow<FlowUiState> = _flowUiState.asStateFlow()
|
||||
|
||||
fun sync() {
|
||||
viewModelScope.launch(ioDispatcher) {
|
||||
applicationScope.launch(ioDispatcher) {
|
||||
rssService.get().doSync()
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +39,7 @@ class FlowViewModel @Inject constructor(
|
|||
articleId: String?,
|
||||
conditions: MarkAsReadConditions,
|
||||
) {
|
||||
viewModelScope.launch(ioDispatcher) {
|
||||
applicationScope.launch(ioDispatcher) {
|
||||
rssService.get().markAsRead(
|
||||
groupId = groupId,
|
||||
feedId = feedId,
|
||||
|
|
|
@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope
|
|||
import androidx.paging.ItemSnapshotList
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
@ -17,9 +18,10 @@ import me.ash.reader.domain.model.article.ArticleFlowItem
|
|||
import me.ash.reader.domain.model.article.ArticleWithFeed
|
||||
import me.ash.reader.domain.model.feed.Feed
|
||||
import me.ash.reader.domain.service.RssService
|
||||
import me.ash.reader.infrastructure.di.ApplicationScope
|
||||
import me.ash.reader.infrastructure.di.IODispatcher
|
||||
import me.ash.reader.infrastructure.rss.RssHelper
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
|
@ -28,6 +30,8 @@ class ReadingViewModel @Inject constructor(
|
|||
private val rssHelper: RssHelper,
|
||||
@IODispatcher
|
||||
private val ioDispatcher: CoroutineDispatcher,
|
||||
@ApplicationScope
|
||||
private val applicationScope: CoroutineScope,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _readingUiState = MutableStateFlow(ReadingUiState())
|
||||
|
@ -110,7 +114,7 @@ class ReadingViewModel @Inject constructor(
|
|||
|
||||
fun updateReadStatus(isUnread: Boolean) {
|
||||
currentArticle?.run {
|
||||
viewModelScope.launch(ioDispatcher) {
|
||||
applicationScope.launch(ioDispatcher) {
|
||||
_readingUiState.update { it.copy(isUnread = isUnread) }
|
||||
rssService.get().markAsRead(
|
||||
groupId = null,
|
||||
|
@ -128,7 +132,7 @@ class ReadingViewModel @Inject constructor(
|
|||
fun markAsUnread() = updateReadStatus(isUnread = true)
|
||||
|
||||
fun updateStarredStatus(isStarred: Boolean) {
|
||||
viewModelScope.launch(ioDispatcher) {
|
||||
applicationScope.launch(ioDispatcher) {
|
||||
_readingUiState.update { it.copy(isStarred = isStarred) }
|
||||
currentArticle?.let {
|
||||
rssService.get().markAsStarred(
|
||||
|
|
|
@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
@ -18,6 +19,7 @@ import me.ash.reader.domain.model.account.Account
|
|||
import me.ash.reader.domain.service.AccountService
|
||||
import me.ash.reader.domain.service.OpmlService
|
||||
import me.ash.reader.domain.service.RssService
|
||||
import me.ash.reader.infrastructure.di.ApplicationScope
|
||||
import me.ash.reader.infrastructure.di.DefaultDispatcher
|
||||
import me.ash.reader.infrastructure.di.IODispatcher
|
||||
import me.ash.reader.infrastructure.di.MainDispatcher
|
||||
|
@ -34,6 +36,8 @@ class AccountViewModel @Inject constructor(
|
|||
private val defaultDispatcher: CoroutineDispatcher,
|
||||
@MainDispatcher
|
||||
private val mainDispatcher: CoroutineDispatcher,
|
||||
@ApplicationScope
|
||||
private val applicationScope: CoroutineScope,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _accountUiState = MutableStateFlow(AccountUiState())
|
||||
|
@ -48,7 +52,7 @@ class AccountViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun update(accountId: Int, block: Account.() -> Unit) {
|
||||
viewModelScope.launch(ioDispatcher) {
|
||||
applicationScope.launch(ioDispatcher) {
|
||||
accountService.update(accountId, block)
|
||||
rssService.get(accountId).clearAuthorization()
|
||||
}
|
||||
|
@ -101,7 +105,7 @@ class AccountViewModel @Inject constructor(
|
|||
|
||||
fun addAccount(account: Account, callback: (account: Account?, exception: Exception?) -> Unit) {
|
||||
setLoading(true)
|
||||
addAccountJob = viewModelScope.launch(ioDispatcher) {
|
||||
addAccountJob = applicationScope.launch(ioDispatcher) {
|
||||
val addAccount = accountService.addAccount(account)
|
||||
try {
|
||||
if (rssService.get(addAccount.type.id).validCredentials(account)) {
|
||||
|
|
Loading…
Reference in New Issue