Refactor repository coroutine
This commit is contained in:
parent
004005d8be
commit
e1e43019f5
|
@ -5,10 +5,11 @@ import androidx.hilt.work.HiltWorkerFactory
|
|||
import androidx.work.Configuration
|
||||
import androidx.work.WorkManager
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.data.module.ApplicationScope
|
||||
import me.ash.reader.data.module.DispatcherDefault
|
||||
import me.ash.reader.data.repository.*
|
||||
import me.ash.reader.data.source.OpmlLocalDataSource
|
||||
import me.ash.reader.data.source.ReaderDatabase
|
||||
|
@ -57,9 +58,13 @@ class App : Application(), Configuration.Provider {
|
|||
@ApplicationScope
|
||||
lateinit var applicationScope: CoroutineScope
|
||||
|
||||
@Inject
|
||||
@DispatcherDefault
|
||||
lateinit var dispatcherDefault: CoroutineDispatcher
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
applicationScope.launch(Dispatchers.IO) {
|
||||
applicationScope.launch(dispatcherDefault) {
|
||||
accountInit()
|
||||
workerInit()
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ import java.io.IOException
|
|||
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
|
||||
val Context.currentAccountId: Int
|
||||
get() = this.dataStore.get(DataStoreKeys.CurrentAccountId)!!
|
||||
val Context.currentAccountType: Int
|
||||
get() = this.dataStore.get(DataStoreKeys.CurrentAccountType)!!
|
||||
|
||||
suspend fun <T> DataStore<Preferences>.put(dataStoreKeys: DataStoreKeys<T>, value: T) {
|
||||
this.edit {
|
||||
|
|
|
@ -7,7 +7,7 @@ import androidx.paging.PagingSource
|
|||
import androidx.work.*
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import me.ash.reader.currentAccountId
|
||||
|
@ -32,6 +32,7 @@ abstract class AbstractRssRepository constructor(
|
|||
private val feedDao: FeedDao,
|
||||
private val rssNetworkDataSource: RssNetworkDataSource,
|
||||
private val workManager: WorkManager,
|
||||
private val dispatcherIO: CoroutineDispatcher,
|
||||
) {
|
||||
data class SyncState(
|
||||
val feedCount: Int = 0,
|
||||
|
@ -59,11 +60,11 @@ abstract class AbstractRssRepository constructor(
|
|||
}
|
||||
|
||||
fun pullGroups(): Flow<MutableList<Group>> {
|
||||
return groupDao.queryAllGroup(context.currentAccountId).flowOn(Dispatchers.IO)
|
||||
return groupDao.queryAllGroup(context.currentAccountId).flowOn(dispatcherIO)
|
||||
}
|
||||
|
||||
fun pullFeeds(): Flow<MutableList<GroupWithFeed>> {
|
||||
return groupDao.queryAllGroupWithFeedAsFlow(context.currentAccountId).flowOn(Dispatchers.IO)
|
||||
return groupDao.queryAllGroupWithFeedAsFlow(context.currentAccountId).flowOn(dispatcherIO)
|
||||
}
|
||||
|
||||
fun pullArticles(
|
||||
|
@ -72,7 +73,6 @@ abstract class AbstractRssRepository constructor(
|
|||
isStarred: Boolean = false,
|
||||
isUnread: Boolean = false,
|
||||
): PagingSource<Int, ArticleWithFeed> {
|
||||
Log.i("RLog", "thread:pullArticles ${Thread.currentThread().name}")
|
||||
val accountId = context.currentAccountId
|
||||
Log.i(
|
||||
"RLog",
|
||||
|
@ -107,7 +107,6 @@ abstract class AbstractRssRepository constructor(
|
|||
isStarred: Boolean = false,
|
||||
isUnread: Boolean = false,
|
||||
): Flow<List<ImportantCount>> {
|
||||
Log.i("RLog", "thread:pullImportant ${Thread.currentThread().name}")
|
||||
val accountId = context.currentAccountId
|
||||
Log.i(
|
||||
"RLog",
|
||||
|
@ -119,7 +118,7 @@ abstract class AbstractRssRepository constructor(
|
|||
isUnread -> articleDao
|
||||
.queryImportantCountWhenIsUnread(accountId, isUnread)
|
||||
else -> articleDao.queryImportantCountWhenIsAll(accountId)
|
||||
}.flowOn(Dispatchers.IO)
|
||||
}.flowOn(dispatcherIO)
|
||||
}
|
||||
|
||||
suspend fun findFeedById(id: String): Feed? {
|
||||
|
@ -130,7 +129,7 @@ abstract class AbstractRssRepository constructor(
|
|||
return articleDao.queryById(id)
|
||||
}
|
||||
|
||||
suspend fun isExist(url: String): Boolean {
|
||||
suspend fun isFeedExist(url: String): Boolean {
|
||||
return feedDao.queryByLink(context.currentAccountId, url).isNotEmpty()
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,11 @@ import android.content.Context
|
|||
import android.util.Log
|
||||
import androidx.work.WorkManager
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import me.ash.reader.*
|
||||
import me.ash.reader.currentAccountId
|
||||
import me.ash.reader.data.account.AccountDao
|
||||
import me.ash.reader.data.article.Article
|
||||
import me.ash.reader.data.article.ArticleDao
|
||||
|
@ -13,11 +16,16 @@ import me.ash.reader.data.feed.Feed
|
|||
import me.ash.reader.data.feed.FeedDao
|
||||
import me.ash.reader.data.group.Group
|
||||
import me.ash.reader.data.group.GroupDao
|
||||
import me.ash.reader.data.module.ApplicationScope
|
||||
import me.ash.reader.data.module.DispatcherDefault
|
||||
import me.ash.reader.data.module.DispatcherIO
|
||||
import me.ash.reader.data.source.FeverApiDataSource
|
||||
import me.ash.reader.data.source.RssNetworkDataSource
|
||||
import me.ash.reader.spacerDollar
|
||||
import net.dankito.readability4j.extended.Readability4JExtended
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.collections.set
|
||||
|
||||
class FeverRssRepository @Inject constructor(
|
||||
@ApplicationContext
|
||||
|
@ -29,10 +37,17 @@ class FeverRssRepository @Inject constructor(
|
|||
private val feverApiDataSource: FeverApiDataSource,
|
||||
private val accountDao: AccountDao,
|
||||
rssNetworkDataSource: RssNetworkDataSource,
|
||||
@ApplicationScope
|
||||
private val applicationScope: CoroutineScope,
|
||||
@DispatcherDefault
|
||||
private val dispatcherDefault: CoroutineDispatcher,
|
||||
@DispatcherIO
|
||||
private val dispatcherIO: CoroutineDispatcher,
|
||||
workManager: WorkManager,
|
||||
) : AbstractRssRepository(
|
||||
context, accountDao, articleDao, groupDao,
|
||||
feedDao, rssNetworkDataSource, workManager,
|
||||
dispatcherIO
|
||||
) {
|
||||
override suspend fun updateArticleInfo(article: Article) {
|
||||
articleDao.update(article)
|
||||
|
@ -58,6 +73,7 @@ class FeverRssRepository @Inject constructor(
|
|||
}
|
||||
|
||||
override suspend fun sync() {
|
||||
applicationScope.launch(dispatcherDefault) {
|
||||
mutex.withLock {
|
||||
val accountId = context.currentAccountId
|
||||
|
||||
|
@ -143,4 +159,5 @@ class FeverRssRepository @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,11 +11,7 @@ import androidx.core.app.NotificationCompat
|
|||
import androidx.core.content.ContextCompat.getSystemService
|
||||
import androidx.work.WorkManager
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.*
|
||||
import me.ash.reader.MainActivity
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.currentAccountId
|
||||
|
@ -26,6 +22,9 @@ import me.ash.reader.data.feed.Feed
|
|||
import me.ash.reader.data.feed.FeedDao
|
||||
import me.ash.reader.data.group.Group
|
||||
import me.ash.reader.data.group.GroupDao
|
||||
import me.ash.reader.data.module.ApplicationScope
|
||||
import me.ash.reader.data.module.DispatcherDefault
|
||||
import me.ash.reader.data.module.DispatcherIO
|
||||
import me.ash.reader.data.source.RssNetworkDataSource
|
||||
import me.ash.reader.ui.page.common.ExtraName
|
||||
import me.ash.reader.ui.page.common.NotificationGroupName
|
||||
|
@ -41,10 +40,17 @@ class LocalRssRepository @Inject constructor(
|
|||
private val rssNetworkDataSource: RssNetworkDataSource,
|
||||
private val accountDao: AccountDao,
|
||||
private val groupDao: GroupDao,
|
||||
@ApplicationScope
|
||||
private val applicationScope: CoroutineScope,
|
||||
@DispatcherDefault
|
||||
private val dispatcherDefault: CoroutineDispatcher,
|
||||
@DispatcherIO
|
||||
private val dispatcherIO: CoroutineDispatcher,
|
||||
workManager: WorkManager,
|
||||
) : AbstractRssRepository(
|
||||
context, accountDao, articleDao, groupDao,
|
||||
feedDao, rssNetworkDataSource, workManager,
|
||||
dispatcherIO
|
||||
) {
|
||||
private val notificationManager: NotificationManager =
|
||||
(getSystemService(
|
||||
|
@ -84,8 +90,7 @@ class LocalRssRepository @Inject constructor(
|
|||
}
|
||||
|
||||
override suspend fun sync() {
|
||||
mutex.withLock {
|
||||
withContext(Dispatchers.IO) {
|
||||
applicationScope.launch(dispatcherDefault) {
|
||||
val preTime = System.currentTimeMillis()
|
||||
val accountId = context.currentAccountId
|
||||
val articles = mutableListOf<Article>()
|
||||
|
@ -116,8 +121,7 @@ class LocalRssRepository @Inject constructor(
|
|||
currentFeedName = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.join()
|
||||
}
|
||||
|
||||
data class ArticleNotify(
|
||||
|
@ -127,10 +131,20 @@ class LocalRssRepository @Inject constructor(
|
|||
|
||||
private suspend fun syncFeed(feed: Feed): ArticleNotify {
|
||||
val latest = articleDao.queryLatestByFeedId(context.currentAccountId, feed.id)
|
||||
val articles = rssHelper.queryRssXml(feed, latest?.link).also {
|
||||
if (feed.icon == null && it.isNotEmpty()) {
|
||||
rssHelper.queryRssIcon(feedDao, feed, it.first().link)
|
||||
var articles: List<Article>? = null
|
||||
try {
|
||||
articles = rssHelper.queryRssXml(feed, latest?.link)
|
||||
} catch (e: Exception) {
|
||||
Log.e("RLog", "queryRssXml[${feed.name}]: ${e.message}")
|
||||
return ArticleNotify(listOf(), false)
|
||||
}
|
||||
try {
|
||||
if (feed.icon == null && !articles.isNullOrEmpty()) {
|
||||
rssHelper.queryRssIcon(feedDao, feed, articles.first().link)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("RLog", "queryRssIcon[${feed.name}]: ${e.message}")
|
||||
return ArticleNotify(listOf(), false)
|
||||
}
|
||||
updateSyncState {
|
||||
it.copy(
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
package me.ash.reader.data.repository
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import be.ceau.opml.OpmlWriter
|
||||
import be.ceau.opml.entity.Body
|
||||
import be.ceau.opml.entity.Head
|
||||
import be.ceau.opml.entity.Opml
|
||||
import be.ceau.opml.entity.Outline
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.currentAccountId
|
||||
import me.ash.reader.data.account.AccountDao
|
||||
import me.ash.reader.data.feed.Feed
|
||||
import me.ash.reader.data.feed.FeedDao
|
||||
import me.ash.reader.data.group.GroupDao
|
||||
import me.ash.reader.data.source.OpmlLocalDataSource
|
||||
import me.ash.reader.spacerDollar
|
||||
import java.io.InputStream
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
@ -25,11 +26,12 @@ class OpmlRepository @Inject constructor(
|
|||
private val feedDao: FeedDao,
|
||||
private val accountDao: AccountDao,
|
||||
private val rssRepository: RssRepository,
|
||||
private val opmlLocalDataSource: OpmlLocalDataSource
|
||||
private val opmlLocalDataSource: OpmlLocalDataSource,
|
||||
private val stringsRepository: StringsRepository,
|
||||
) {
|
||||
@Throws(Exception::class)
|
||||
suspend fun saveToDatabase(inputStream: InputStream) {
|
||||
try {
|
||||
val defaultGroup = groupDao.queryById(opmlLocalDataSource.getDefaultGroupId())!!
|
||||
val defaultGroup = groupDao.queryById(getDefaultGroupId())!!
|
||||
val groupWithFeedList =
|
||||
opmlLocalDataSource.parseFileInputStream(inputStream, defaultGroup)
|
||||
groupWithFeedList.forEach { groupWithFeed ->
|
||||
|
@ -39,21 +41,18 @@ class OpmlRepository @Inject constructor(
|
|||
val repeatList = mutableListOf<Feed>()
|
||||
groupWithFeed.feeds.forEach {
|
||||
it.groupId = groupWithFeed.group.id
|
||||
if (rssRepository.get().isExist(it.url)) {
|
||||
if (rssRepository.get().isFeedExist(it.url)) {
|
||||
repeatList.add(it)
|
||||
}
|
||||
}
|
||||
feedDao.insertList((groupWithFeed.feeds subtract repeatList).toList())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("saveToDatabase", "${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveToString(): String? =
|
||||
try {
|
||||
val defaultGroup = groupDao.queryById(opmlLocalDataSource.getDefaultGroupId())!!
|
||||
OpmlWriter().write(
|
||||
@Throws(Exception::class)
|
||||
suspend fun saveToString(): String {
|
||||
val defaultGroup = groupDao.queryById(getDefaultGroupId())!!
|
||||
return OpmlWriter().write(
|
||||
Opml(
|
||||
"2.0",
|
||||
Head(
|
||||
|
@ -85,9 +84,12 @@ class OpmlRepository @Inject constructor(
|
|||
)
|
||||
})
|
||||
)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e("saveToString", "${e.message}")
|
||||
null
|
||||
)!!
|
||||
}
|
||||
|
||||
private fun getDefaultGroupId(): String {
|
||||
val readYouString = stringsRepository.getString(R.string.read_you)
|
||||
val defaultString = stringsRepository.getString(R.string.defaults)
|
||||
return context.currentAccountId.spacerDollar(readYouString + defaultString)
|
||||
}
|
||||
}
|
|
@ -4,17 +4,20 @@ import android.content.Context
|
|||
import android.text.Html
|
||||
import android.util.Log
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.withContext
|
||||
import me.ash.reader.currentAccountId
|
||||
import me.ash.reader.data.article.Article
|
||||
import me.ash.reader.data.feed.Feed
|
||||
import me.ash.reader.data.feed.FeedDao
|
||||
import me.ash.reader.data.feed.FeedWithArticle
|
||||
import me.ash.reader.data.module.DispatcherIO
|
||||
import me.ash.reader.data.source.RssNetworkDataSource
|
||||
import me.ash.reader.spacerDollar
|
||||
import net.dankito.readability4j.Readability4J
|
||||
import net.dankito.readability4j.extended.Readability4JExtended
|
||||
import okhttp3.*
|
||||
import java.io.IOException
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import java.text.ParsePosition
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
@ -24,9 +27,12 @@ class RssHelper @Inject constructor(
|
|||
@ApplicationContext
|
||||
private val context: Context,
|
||||
private val rssNetworkDataSource: RssNetworkDataSource,
|
||||
@DispatcherIO
|
||||
private val dispatcherIO: CoroutineDispatcher,
|
||||
) {
|
||||
@Throws(Exception::class)
|
||||
suspend fun searchFeed(feedLink: String): FeedWithArticle {
|
||||
return withContext(dispatcherIO) {
|
||||
val accountId = context.currentAccountId
|
||||
val parseRss = rssNetworkDataSource.parseRss(feedLink)
|
||||
val feed = Feed(
|
||||
|
@ -36,7 +42,8 @@ class RssHelper @Inject constructor(
|
|||
groupId = "",
|
||||
accountId = accountId,
|
||||
)
|
||||
return FeedWithArticle(feed, queryRssXml(feed))
|
||||
FeedWithArticle(feed, queryRssXml(feed))
|
||||
}
|
||||
}
|
||||
|
||||
fun parseDescriptionContent(link: String, content: String): String {
|
||||
|
@ -46,42 +53,39 @@ class RssHelper @Inject constructor(
|
|||
return element.toString()
|
||||
}
|
||||
|
||||
fun parseFullContent(link: String, title: String, callback: (String) -> Unit) {
|
||||
OkHttpClient()
|
||||
@Throws(Exception::class)
|
||||
suspend fun parseFullContent(link: String, title: String): String {
|
||||
return withContext(dispatcherIO) {
|
||||
val response = OkHttpClient()
|
||||
.newCall(Request.Builder().url(link).build())
|
||||
.enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
callback(e.message.toString())
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
val content = response.body?.string()
|
||||
.execute()
|
||||
val content = response.body!!.string()
|
||||
val readability4J: Readability4J =
|
||||
Readability4JExtended(link, content ?: "")
|
||||
Readability4JExtended(link, content)
|
||||
val articleContent = readability4J.parse().articleContent
|
||||
if (articleContent == null) {
|
||||
callback("")
|
||||
""
|
||||
} else {
|
||||
val h1Element = articleContent.selectFirst("h1")
|
||||
if (h1Element != null && h1Element.hasText() && h1Element.text() == title) {
|
||||
h1Element.remove()
|
||||
}
|
||||
callback(articleContent.toString())
|
||||
articleContent.toString()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
suspend fun queryRssXml(
|
||||
feed: Feed,
|
||||
latestLink: String? = null,
|
||||
): List<Article> {
|
||||
return withContext(dispatcherIO) {
|
||||
val a = mutableListOf<Article>()
|
||||
try {
|
||||
val accountId = context.currentAccountId
|
||||
val parseRss = rssNetworkDataSource.parseRss(feed.url)
|
||||
parseRss.items.forEach {
|
||||
if (latestLink != null && latestLink == it.link) return a
|
||||
if (latestLink != null && latestLink == it.link) return@withContext a
|
||||
Log.i("RLog", "request rss ${feed.name}: ${it.title}")
|
||||
a.add(
|
||||
Article(
|
||||
|
@ -104,27 +108,23 @@ class RssHelper @Inject constructor(
|
|||
)
|
||||
)
|
||||
}
|
||||
return a
|
||||
} catch (e: Exception) {
|
||||
Log.e("RLog", "error ${feed.name}: ${e.message}")
|
||||
return a
|
||||
a
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
suspend fun queryRssIcon(
|
||||
feedDao: FeedDao,
|
||||
feed: Feed,
|
||||
articleLink: String?,
|
||||
articleLink: String,
|
||||
) {
|
||||
try {
|
||||
if (articleLink == null) return
|
||||
withContext(dispatcherIO) {
|
||||
val execute = OkHttpClient()
|
||||
.newCall(Request.Builder().url(articleLink).build())
|
||||
.execute()
|
||||
val content = execute.body?.string()
|
||||
val content = execute.body!!.string()
|
||||
val regex =
|
||||
Regex("""<link(.+?)rel="shortcut icon"(.+?)href="(.+?)"""")
|
||||
if (content != null) {
|
||||
var iconLink = regex
|
||||
.find(content)
|
||||
?.groups?.get(3)
|
||||
|
@ -144,24 +144,22 @@ class RssHelper @Inject constructor(
|
|||
} else {
|
||||
// saveRssIcon(feedDao, feed, "")
|
||||
}
|
||||
} else {
|
||||
// saveRssIcon(feedDao, feed, "")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("RLog", "queryRssIcon: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun saveRssIcon(feedDao: FeedDao, feed: Feed, iconLink: String) {
|
||||
val execute = OkHttpClient()
|
||||
@Throws(Exception::class)
|
||||
suspend fun saveRssIcon(feedDao: FeedDao, feed: Feed, iconLink: String) {
|
||||
withContext(dispatcherIO) {
|
||||
val response = OkHttpClient()
|
||||
.newCall(Request.Builder().url(iconLink).build())
|
||||
.execute()
|
||||
feedDao.update(
|
||||
feed.apply {
|
||||
icon = execute.body?.bytes()
|
||||
icon = response.body!!.bytes()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseDate(
|
||||
inputDate: String, patterns: Array<String?> = arrayOf(
|
||||
|
|
|
@ -2,10 +2,8 @@ package me.ash.reader.data.repository
|
|||
|
||||
import android.content.Context
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import me.ash.reader.DataStoreKeys
|
||||
import me.ash.reader.currentAccountType
|
||||
import me.ash.reader.data.account.Account
|
||||
import me.ash.reader.dataStore
|
||||
import me.ash.reader.get
|
||||
import javax.inject.Inject
|
||||
|
||||
class RssRepository @Inject constructor(
|
||||
|
@ -15,13 +13,11 @@ class RssRepository @Inject constructor(
|
|||
private val feverRssRepository: FeverRssRepository,
|
||||
// private val googleReaderRssRepository: GoogleReaderRssRepository,
|
||||
) {
|
||||
fun get() = when (getAccountType()) {
|
||||
fun get() = when (context.currentAccountType) {
|
||||
Account.Type.LOCAL -> localRssRepository
|
||||
// Account.Type.LOCAL -> feverRssRepository
|
||||
Account.Type.FEVER -> feverRssRepository
|
||||
// Account.Type.GOOGLE_READER -> googleReaderRssRepository
|
||||
else -> throw IllegalStateException("Unknown account type: ${getAccountType()}")
|
||||
else -> throw IllegalStateException("Unknown account type: ${context.currentAccountType}")
|
||||
}
|
||||
|
||||
private fun getAccountType(): Int = context.dataStore.get(DataStoreKeys.CurrentAccountType)!!
|
||||
}
|
||||
|
|
|
@ -3,11 +3,13 @@ package me.ash.reader.data.source
|
|||
import android.content.Context
|
||||
import be.ceau.opml.OpmlParser
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import me.ash.reader.*
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.withContext
|
||||
import me.ash.reader.currentAccountId
|
||||
import me.ash.reader.data.feed.Feed
|
||||
import me.ash.reader.data.group.Group
|
||||
import me.ash.reader.data.group.GroupWithFeed
|
||||
import me.ash.reader.data.repository.StringsRepository
|
||||
import me.ash.reader.data.module.DispatcherIO
|
||||
import java.io.InputStream
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
@ -15,18 +17,15 @@ import javax.inject.Inject
|
|||
class OpmlLocalDataSource @Inject constructor(
|
||||
@ApplicationContext
|
||||
private val context: Context,
|
||||
private val stringsRepository: StringsRepository,
|
||||
@DispatcherIO
|
||||
private val dispatcherIO: CoroutineDispatcher,
|
||||
) {
|
||||
fun getDefaultGroupId(): String {
|
||||
val readYouString = stringsRepository.getString(R.string.read_you)
|
||||
val defaultString = stringsRepository.getString(R.string.defaults)
|
||||
return context.dataStore
|
||||
.get(DataStoreKeys.CurrentAccountId)!!
|
||||
.spacerDollar(readYouString + defaultString)
|
||||
}
|
||||
|
||||
// @Throws(XmlPullParserException::class, IOException::class)
|
||||
fun parseFileInputStream(inputStream: InputStream, defaultGroup: Group): List<GroupWithFeed> {
|
||||
@Throws(Exception::class)
|
||||
suspend fun parseFileInputStream(
|
||||
inputStream: InputStream,
|
||||
defaultGroup: Group
|
||||
): List<GroupWithFeed> {
|
||||
return withContext(dispatcherIO) {
|
||||
val accountId = context.currentAccountId
|
||||
val opml = OpmlParser().parse(inputStream)
|
||||
val groupWithFeedList = mutableListOf<GroupWithFeed>().also {
|
||||
|
@ -87,7 +86,8 @@ class OpmlLocalDataSource @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
return groupWithFeedList
|
||||
groupWithFeedList
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<GroupWithFeed>.addGroup(group: Group) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package me.ash.reader.ui.page.home.drawer.feed
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
|
@ -8,10 +9,10 @@ import androidx.compose.material.icons.rounded.DeleteOutline
|
|||
import androidx.compose.material.icons.rounded.RssFeed
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
|
@ -31,7 +32,6 @@ fun FeedOptionDrawer(
|
|||
viewModel: FeedOptionViewModel = hiltViewModel(),
|
||||
content: @Composable () -> Unit = {},
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val viewState = viewModel.viewState.collectAsStateValue()
|
||||
val feed = viewState.feed
|
||||
|
||||
|
|
|
@ -49,14 +49,22 @@ class FeedsViewModel @Inject constructor(
|
|||
|
||||
private fun importFromInputStream(inputStream: InputStream) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
opmlRepository.saveToDatabase(inputStream)
|
||||
rssRepository.get().doSync()
|
||||
} catch (e: Exception) {
|
||||
Log.e("FeedsViewModel", "importFromInputStream: ", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun exportAsOpml(callback: (String) -> Unit = {}) {
|
||||
viewModelScope.launch(Dispatchers.Default) {
|
||||
opmlRepository.saveToString()?.let { callback(it) }
|
||||
try {
|
||||
callback(opmlRepository.saveToString())
|
||||
} catch (e: Exception) {
|
||||
Log.e("FeedsViewModel", "exportAsOpml: ", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,7 +82,6 @@ class FeedsViewModel @Inject constructor(
|
|||
rssRepository.get().pullFeeds(),
|
||||
rssRepository.get().pullImportant(isStarred, isUnread),
|
||||
) { groupWithFeedList, importantList ->
|
||||
Log.i("RLog", "thread:combine ${Thread.currentThread().name}")
|
||||
val groupImportantMap = mutableMapOf<String, Int>()
|
||||
val feedImportantMap = mutableMapOf<String, Int>()
|
||||
importantList.groupBy { it.groupId }.forEach { (i, list) ->
|
||||
|
@ -109,8 +116,6 @@ class FeedsViewModel @Inject constructor(
|
|||
}.onStart {
|
||||
|
||||
}.onEach { groupWithFeedList ->
|
||||
Log.i("RLog", "thread:onEach ${Thread.currentThread().name}")
|
||||
|
||||
_viewState.update {
|
||||
it.copy(
|
||||
filter = when {
|
||||
|
|
|
@ -148,7 +148,7 @@ class SubscribeViewModel @Inject constructor(
|
|||
lockLinkInput = true,
|
||||
)
|
||||
}
|
||||
if (rssRepository.get().isExist(_viewState.value.linkContent)) {
|
||||
if (rssRepository.get().isFeedExist(_viewState.value.linkContent)) {
|
||||
_viewState.update {
|
||||
it.copy(
|
||||
title = stringsRepository.getString(R.string.subscribe),
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package me.ash.reader.ui.page.home.flow
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
|
@ -55,7 +54,6 @@ class FlowViewModel @Inject constructor(
|
|||
_viewState.update {
|
||||
it.copy(
|
||||
pagingData = Pager(PagingConfig(pageSize = 10)) {
|
||||
Log.i("RLog", "thread:Pager ${Thread.currentThread().name}")
|
||||
rssRepository.get().pullArticles(
|
||||
groupId = filterState.group?.id,
|
||||
feedId = filterState.feed?.id,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package me.ash.reader.ui.page.home.read
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
|
@ -55,12 +56,23 @@ class ReadViewModel @Inject constructor(
|
|||
|
||||
private fun renderFullContent() {
|
||||
changeLoading(true)
|
||||
rssHelper.parseFullContent(
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
_viewState.update {
|
||||
it.copy(
|
||||
content = rssHelper.parseFullContent(
|
||||
_viewState.value.articleWithFeed?.article?.link ?: "",
|
||||
_viewState.value.articleWithFeed?.article?.title ?: ""
|
||||
) { content ->
|
||||
)
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.i("RLog", "renderFullContent: ${e.message}")
|
||||
_viewState.update {
|
||||
it.copy(content = content)
|
||||
it.copy(
|
||||
content = e.message
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user