Switch to Rome (#50)

* Switch to Rome

* Fix some styles
This commit is contained in:
Ashinch 2022-05-07 00:28:17 +08:00 committed by GitHub
parent 5e569d1303
commit 4c7ff2a84e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 59 additions and 96 deletions

View File

@ -85,9 +85,8 @@ dependencies {
// https://github.com/dankito/Readability4J
implementation "net.dankito.readability4j:readability4j:$readability4j"
// https://github.com/muhrifqii/ParseRSS/releases
implementation "com.github.muhrifqii.ParseRSS:parserss:$parseRSS"
implementation "com.github.muhrifqii.ParseRSS:retrofit:$parseRSS"
// https://mvnrepository.com/artifact/com.rometools/rome
implementation "com.rometools:rome:$rome"
// https://coil-kt.github.io/coil/changelog/
implementation("io.coil-kt:coil-compose:$coil")

View File

@ -30,3 +30,6 @@
-dontwarn org.xmlpull.v1.XmlPullParser
-dontwarn org.xmlpull.v1.XmlSerializer
-keep class org.xmlpull.v1.* {*;}
# Rome
-keep class com.rometools.** { *; }

View File

@ -14,7 +14,6 @@ import me.ash.reader.data.repository.*
import me.ash.reader.data.source.AppNetworkDataSource
import me.ash.reader.data.source.OpmlLocalDataSource
import me.ash.reader.data.source.ReaderDatabase
import me.ash.reader.data.source.RssNetworkDataSource
import me.ash.reader.ui.ext.*
import javax.inject.Inject
@ -35,9 +34,6 @@ class App : Application(), Configuration.Provider {
@Inject
lateinit var opmlLocalDataSource: OpmlLocalDataSource
@Inject
lateinit var rssNetworkDataSource: RssNetworkDataSource
@Inject
lateinit var rssHelper: RssHelper

View File

@ -7,7 +7,6 @@ import dagger.hilt.components.SingletonComponent
import me.ash.reader.data.source.AppNetworkDataSource
import me.ash.reader.data.source.FeverApiDataSource
import me.ash.reader.data.source.GoogleReaderApiDataSource
import me.ash.reader.data.source.RssNetworkDataSource
import javax.inject.Singleton
@Module
@ -19,11 +18,6 @@ object RetrofitModule {
fun provideAppNetworkDataSource(): AppNetworkDataSource =
AppNetworkDataSource.getInstance()
@Provides
@Singleton
fun provideRssNetworkDataSource(): RssNetworkDataSource =
RssNetworkDataSource.getInstance()
@Provides
@Singleton
fun provideFeverApiDataSource(): FeverApiDataSource =

View File

@ -15,7 +15,6 @@ import me.ash.reader.data.dao.ArticleDao
import me.ash.reader.data.dao.FeedDao
import me.ash.reader.data.dao.GroupDao
import me.ash.reader.data.entity.*
import me.ash.reader.data.source.RssNetworkDataSource
import me.ash.reader.ui.ext.currentAccountId
import java.util.*
import java.util.concurrent.TimeUnit
@ -26,7 +25,6 @@ abstract class AbstractRssRepository constructor(
private val articleDao: ArticleDao,
private val groupDao: GroupDao,
private val feedDao: FeedDao,
private val rssNetworkDataSource: RssNetworkDataSource,
private val workManager: WorkManager,
private val dispatcherIO: CoroutineDispatcher,
) {

View File

@ -28,7 +28,6 @@ import me.ash.reader.data.entity.Group
import me.ash.reader.data.module.DispatcherDefault
import me.ash.reader.data.module.DispatcherIO
import me.ash.reader.data.repository.SyncWorker.Companion.setIsSyncing
import me.ash.reader.data.source.RssNetworkDataSource
import me.ash.reader.ui.ext.currentAccountId
import me.ash.reader.ui.ext.spacerDollar
import me.ash.reader.ui.page.common.ExtraName
@ -42,7 +41,6 @@ class LocalRssRepository @Inject constructor(
private val articleDao: ArticleDao,
private val feedDao: FeedDao,
private val rssHelper: RssHelper,
private val rssNetworkDataSource: RssNetworkDataSource,
private val accountDao: AccountDao,
private val groupDao: GroupDao,
@DispatcherDefault
@ -52,8 +50,7 @@ class LocalRssRepository @Inject constructor(
workManager: WorkManager,
) : AbstractRssRepository(
context, accountDao, articleDao, groupDao,
feedDao, rssNetworkDataSource, workManager,
dispatcherIO
feedDao, workManager, dispatcherIO
) {
private val notificationManager: NotificationManagerCompat =
NotificationManagerCompat.from(context).apply {

View File

@ -3,6 +3,9 @@ package me.ash.reader.data.repository
import android.content.Context
import android.text.Html
import android.util.Log
import com.rometools.rome.feed.synd.SyndFeed
import com.rometools.rome.io.SyndFeedInput
import com.rometools.rome.io.XmlReader
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
@ -11,13 +14,13 @@ 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.module.DispatcherIO
import me.ash.reader.data.source.RssNetworkDataSource
import me.ash.reader.ui.ext.currentAccountId
import me.ash.reader.ui.ext.spacerDollar
import net.dankito.readability4j.Readability4J
import net.dankito.readability4j.extended.Readability4JExtended
import okhttp3.OkHttpClient
import okhttp3.Request
import java.net.URL
import java.text.ParsePosition
import java.text.SimpleDateFormat
import java.util.*
@ -26,7 +29,6 @@ import javax.inject.Inject
class RssHelper @Inject constructor(
@ApplicationContext
private val context: Context,
private val rssNetworkDataSource: RssNetworkDataSource,
@DispatcherIO
private val dispatcherIO: CoroutineDispatcher,
) {
@ -34,7 +36,7 @@ class RssHelper @Inject constructor(
suspend fun searchFeed(feedLink: String): FeedWithArticle {
return withContext(dispatcherIO) {
val accountId = context.currentAccountId
val parseRss = rssNetworkDataSource.parseRss(feedLink)
val parseRss: SyndFeed = SyndFeedInput().build(XmlReader(URL(feedLink)))
val feed = Feed(
id = accountId.spacerDollar(UUID.randomUUID().toString()),
name = parseRss.title!!,
@ -83,28 +85,36 @@ class RssHelper @Inject constructor(
return withContext(dispatcherIO) {
val a = mutableListOf<Article>()
val accountId = context.currentAccountId
val parseRss = rssNetworkDataSource.parseRss(feed.url)
parseRss.items.forEach {
val parseRss: SyndFeed = SyndFeedInput().build(XmlReader(URL(feed.url)))
parseRss.entries.forEach {
if (latestLink != null && latestLink == it.link) return@withContext a
Log.i("RLog", "request rss:\n${feed.name},${feed.url}\n${it.title}\n${it.link}\n")
val desc = it.description?.value
val content = it.contents
.takeIf { it.isNotEmpty() }
?.let { it.joinToString("\n") { it.value } }
Log.i(
"RLog",
"request rss:\n" +
"name: ${feed.name}\n" +
"url: ${feed.url}\n" +
"title: ${it.title}\n" +
"desc: ${desc}\n" +
"content: ${content}\n"
)
a.add(
Article(
id = accountId.spacerDollar(UUID.randomUUID().toString()),
accountId = accountId,
feedId = feed.id,
date = (it.publishDate ?: it.lastUpdated).toString().let {
try {
Date(it)
} catch (e: IllegalArgumentException) {
parseDate(it) ?: Date()
}
},
date = it.publishedDate ?: it.updatedDate ?: Date(),
title = Html.fromHtml(it.title.toString()).toString(),
author = it.author?.name,
rawDescription = it.description ?: it.summary ?: "",
shortDescription =
(Readability4JExtended("", it.description ?: it.summary ?: "")
.parse().textContent ?: "").take(100).trim(),
author = it.author,
rawDescription = (desc ?: content) ?: "",
shortDescription = (Readability4JExtended("", desc ?: content ?: "")
.parse().textContent ?: "")
.take(100)
.trim(),
fullContent = content,
link = it.link ?: "",
)
)

View File

@ -1,9 +1,7 @@
package me.ash.reader.data.source
import com.github.muhrifqii.parserss.ParseRSS
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import org.xmlpull.v1.XmlPullParserFactory
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
@ -48,7 +46,6 @@ interface FeverApiDataSource {
fun getInstance(): FeverApiDataSource {
return instance ?: synchronized(this) {
ParseRSS.init(XmlPullParserFactory.newInstance())
instance ?: Retrofit.Builder()
.baseUrl("http://10.0.2.2/api/")
.addConverterFactory(GsonConverterFactory.create())

View File

@ -1,7 +1,5 @@
package me.ash.reader.data.source
import com.github.muhrifqii.parserss.ParseRSS
import org.xmlpull.v1.XmlPullParserFactory
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
@ -33,7 +31,6 @@ interface GoogleReaderApiDataSource {
fun getInstance(): GoogleReaderApiDataSource {
return instance ?: synchronized(this) {
ParseRSS.init(XmlPullParserFactory.newInstance())
instance ?: Retrofit.Builder()
.baseUrl("http://10.0.2.2/api/greader.php/")
.addConverterFactory(GsonConverterFactory.create())

View File

@ -1,30 +0,0 @@
package me.ash.reader.data.source
import com.github.muhrifqii.parserss.ParseRSS
import com.github.muhrifqii.parserss.RSSFeedObject
import com.github.muhrifqii.parserss.retrofit.ParseRSSConverterFactory
import org.xmlpull.v1.XmlPullParserFactory
import retrofit2.Retrofit
import retrofit2.http.GET
import retrofit2.http.Url
interface RssNetworkDataSource {
@GET
suspend fun parseRss(@Url url: String): RSSFeedObject
companion object {
private var instance: RssNetworkDataSource? = null
fun getInstance(): RssNetworkDataSource {
return instance ?: synchronized(this) {
ParseRSS.init(XmlPullParserFactory.newInstance())
instance ?: Retrofit.Builder()
.baseUrl("https://api.feeddd.org/feeds/")
.addConverterFactory(ParseRSSConverterFactory.create<RSSFeedObject>())
.build().create(RssNetworkDataSource::class.java).also {
instance = it
}
}
}
}
}

View File

@ -6,10 +6,7 @@ import android.net.http.SslError
import android.util.Log
import android.webkit.*
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
@ -122,11 +119,12 @@ fun WebView(
// }
AndroidView(
modifier = modifier,
modifier = modifier,//.padding(horizontal = if (content.contains("class=\"page\"")) 0.dp else 24.dp),
factory = { webView },
update = {
it.apply {
Log.i("RLog", "CustomWebView: ${content}")
settings.javaScriptEnabled = true
loadDataWithBaseURL(
null,
getStyle(color) + content,
@ -138,10 +136,12 @@ fun WebView(
)
}
@Stable
fun argbToCssColor(argb: Int): String = String.format("#%06X", 0xFFFFFF and argb)
@Stable
fun getStyle(argb: Int): String = """
<head><style>
<html><head><style>
*{
padding: 0;
margin: 0;
@ -154,14 +154,13 @@ fun getStyle(argb: Int): String = """
url('/android_asset_font/font/google_sans_text_bold.TTF');
}
.page {
html {
padding: 0 24px;
}
img, video {
img, video, iframe {
margin: 0 -24px 20px;
width: calc(100% + 48px);
height: auto;
border-top: 1px solid ${argbToCssColor(argb)}08;
border-bottom: 1px solid ${argbToCssColor(argb)}08;
}
@ -213,5 +212,5 @@ h1,h2,h3,h4,h5,h6,figure,br {
}
.element::-webkit-scrollbar { width: 0 !important }
</style></head>
</style></head></html>
"""

View File

@ -190,7 +190,7 @@ fun FeedsPage(
item {
Banner(
title = filterState.filter.getName(),
desc = feedsViewState.importantCount,
desc = feedsViewState.importantCount.ifEmpty { stringResource(R.string.loading) },
icon = filterState.filter.iconOutline,
action = {
Icon(

View File

@ -121,7 +121,7 @@ fun ArticleItem(
overflow = TextOverflow.Ellipsis,
)
// Description
if (articleListDesc.value) {
if (articleListDesc.value && articleWithFeed.article.shortDescription.isNotBlank()) {
Text(
text = articleWithFeed.article.shortDescription,
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f),

View File

@ -273,6 +273,7 @@ fun FlowPage(
if (pagingItems.loadState.source.refresh is LoadState.NotLoading && pagingItems.itemCount != 0) {
Spacer(modifier = Modifier.height(64.dp))
}
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
}
}
}

View File

@ -46,12 +46,14 @@ fun Header(
)
Spacer(modifier = Modifier.height(4.dp))
articleWithFeed.article.author?.let {
if (it.isNotEmpty()) {
Text(
text = articleWithFeed.article.author,
text = it,
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f),
style = MaterialTheme.typography.labelMedium,
)
}
}
Text(
text = articleWithFeed.feed.name,
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f),

View File

@ -54,10 +54,8 @@ class ReadViewModel @Inject constructor(
private fun renderDescriptionContent() {
_viewState.update {
it.copy(
content = rssHelper.parseDescriptionContent(
link = it.articleWithFeed?.article?.link ?: "",
content = it.articleWithFeed?.article?.rawDescription ?: "",
)
content = it.articleWithFeed?.article?.fullContent
?: it.articleWithFeed?.article?.rawDescription ?: "",
)
}
}

View File

@ -8,6 +8,7 @@
<string name="starred_desc">%1$d 项已加星标</string>
<string name="feeds">分组</string>
<string name="syncing">正在同步…</string>
<string name="loading">加载中…</string>
<string name="expand_less">收缩</string>
<string name="expand_more">展开</string>
<string name="confirm">确认</string>

View File

@ -8,6 +8,7 @@
<string name="starred_desc">%1$d Starred Items</string>
<string name="feeds">Feeds</string>
<string name="syncing">Syncing…</string>
<string name="loading">Loading…</string>
<string name="expand_less">Expand Less</string>
<string name="expand_more">Expand More</string>
<string name="confirm">Confirm</string>

View File

@ -12,7 +12,7 @@ buildscript {
profileinstaller = '1.2.0-alpha02'
retrofit2 = '2.9.0'
coil = '2.0.0-rc03'
parseRSS = '0.6.0'
rome = '1.18.0'
readability4j = '1.0.8'
opmlParser = '2.2.0'
androidSVG = '1.4'