Skip to content

Commit

Permalink
add rss data mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
Tlaster committed Jan 23, 2025
1 parent 6e37c80 commit 71fd76f
Show file tree
Hide file tree
Showing 16 changed files with 209 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package dev.dimension.flare.ui.component.status

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import dev.dimension.flare.ui.component.NetworkImage
import dev.dimension.flare.ui.model.UiTimeline

@Composable
internal fun FeedComponent(
data: UiTimeline.ItemContent.Feed,
modifier: Modifier = Modifier,
) {
val uriHandler = LocalUriHandler.current
Column(
modifier =
modifier
.clickable {
uriHandler.openUri(data.url)
},
) {
data.image?.let {
NetworkImage(
model = it,
contentDescription = data.title,
modifier =
Modifier
.aspectRatio(16f / 9f),
)
}
Text(
text = data.title,
style = MaterialTheme.typography.titleMedium,
)
data.description?.let {
Text(text = it)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ private fun ItemContentComponent(
modifier
.padding(bottom = 8.dp),
)

is UiTimeline.ItemContent.Feed -> {
FeedComponent(
data = item,
modifier = modifier,
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,6 @@ internal fun List<ListNotificationsNotification>.toDb(
),
accountKey = accountKey,
userKey = null,
platformType = PlatformType.Bluesky,
content = content,
text = null,
),
Expand Down Expand Up @@ -278,7 +277,6 @@ internal fun List<ListNotificationsNotification>.toDb(
),
accountKey = accountKey,
userKey = null,
platformType = PlatformType.Bluesky,
content = content,
text = null,
),
Expand Down Expand Up @@ -311,7 +309,6 @@ internal fun List<ListNotificationsNotification>.toDb(
),
accountKey = accountKey,
userKey = user.userKey,
platformType = PlatformType.Bluesky,
content = content,
text = null,
),
Expand Down Expand Up @@ -349,7 +346,6 @@ private fun ListNotificationsNotification.toDbStatus(accountKey: MicroBlogKey):
uri.atUri + "_" + user.userKey,
accountKey.host,
),
platformType = PlatformType.Bluesky,
userKey = user.userKey,
content = StatusContent.BlueskyNotification.Normal(this),
accountKey = accountKey,
Expand Down Expand Up @@ -381,7 +377,6 @@ internal fun List<FeedViewPost>.toDbPagingTimeline(
it.post.uri.atUri + "_reblog_${user.userKey}",
accountKey.host,
),
platformType = PlatformType.Bluesky,
userKey =
data.value.by
.toDbUser(accountKey.host)
Expand Down Expand Up @@ -429,7 +424,6 @@ private fun PostView.toDbStatusWithUser(accountKey: MicroBlogKey): DbStatusWithU
uri.atUri,
host = user.userKey.host,
),
platformType = PlatformType.Bluesky,
content = StatusContent.Bluesky(this),
userKey = user.userKey,
accountKey = accountKey,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ private fun Notification.toDbStatus(accountKey: MicroBlogKey): DbStatus {
this.id ?: throw IllegalStateException("id is null"),
user.userKey.host,
),
platformType = PlatformType.Mastodon,
userKey = user.userKey,
content = StatusContent.MastodonNotification(this),
accountKey = accountKey,
Expand Down Expand Up @@ -119,7 +118,6 @@ private fun Status.toDbStatusWithUser(accountKey: MicroBlogKey): DbStatusWithUse
id ?: throw IllegalArgumentException("mastodon Status.idStr should not be null"),
host = user.userKey.host,
),
platformType = PlatformType.Mastodon,
content =
dev.dimension.flare.data.database.cache.model.StatusContent
.Mastodon(this),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ private fun Notification.toDbStatus(accountKey: MicroBlogKey): DbStatus {
this.id,
accountKey.host,
),
platformType = PlatformType.Misskey,
userKey = user?.userKey,
content = StatusContent.MisskeyNotification(this),
accountKey = accountKey,
Expand Down Expand Up @@ -188,7 +187,6 @@ private fun Note.toDbStatusWithUser(accountKey: MicroBlogKey): DbStatusWithUser
id = id,
host = user.userKey.host,
),
platformType = PlatformType.Misskey,
content = StatusContent.Misskey(this),
userKey = user.userKey,
accountKey = accountKey,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ private fun Status.toDbStatus(accountKey: MicroBlogKey): DbStatus =
statusKey = MicroBlogKey(id = id, host = vvoHost),
accountKey = accountKey,
userKey = user?.id?.let { MicroBlogKey(id = it.toString(), host = vvoHost) },
platformType = dev.dimension.flare.model.PlatformType.VVo,
content =
dev.dimension.flare.data.database.cache.model.StatusContent
.VVO(data = this),
Expand Down Expand Up @@ -114,7 +113,6 @@ private fun Comment.toDbStatus(accountKey: MicroBlogKey): DbStatus =
statusKey = MicroBlogKey(id = id, host = vvoHost),
accountKey = accountKey,
userKey = user?.id?.let { MicroBlogKey(id = it.toString(), host = vvoHost) },
platformType = dev.dimension.flare.model.PlatformType.VVo,
content =
dev.dimension.flare.data.database.cache.model.StatusContent
.VVOComment(data = this),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ private fun toDbStatusWithUser(
id = tweet.restId,
host = user.userKey.host,
),
platformType = PlatformType.xQt,
content = StatusContent.XQT(tweet),
userKey = user.userKey,
accountKey = accountKey,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import androidx.room.TypeConverter
import dev.dimension.flare.common.decodeJson
import dev.dimension.flare.common.encodeJson
import dev.dimension.flare.model.MicroBlogKey
import dev.dimension.flare.model.PlatformType

@Entity(
indices = [Index(value = ["statusKey", "accountKey"], unique = true)],
Expand All @@ -16,7 +15,6 @@ internal data class DbStatus(
val statusKey: MicroBlogKey,
val accountKey: MicroBlogKey,
val userKey: MicroBlogKey?,
val platformType: PlatformType,
val content: StatusContent,
val text: String?, // For Searching
@PrimaryKey
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package dev.dimension.flare.data.datasource.rss

import androidx.paging.Pager
import androidx.paging.PagingConfig

internal object RssDataSource {
fun fetch(url: String) =
Pager(
config =
PagingConfig(
pageSize = 20,
),
pagingSourceFactory = { RssTimelinePagingSource(url) },
).flow
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package dev.dimension.flare.data.datasource.rss

import androidx.paging.ExperimentalPagingApi
import androidx.paging.PagingSource
import androidx.paging.PagingState
import dev.dimension.flare.data.network.rss.RssService
import dev.dimension.flare.ui.model.UiTimeline
import dev.dimension.flare.ui.model.mapper.render

@OptIn(ExperimentalPagingApi::class)
internal class RssTimelinePagingSource(
private val url: String,
) : PagingSource<Int, UiTimeline>() {
override fun getRefreshKey(state: PagingState<Int, UiTimeline>): Int? = null

override suspend fun load(params: LoadParams<Int>): LoadResult<Int, UiTimeline> {
return try {
val response = RssService.fetch(url).render()
return LoadResult.Page(
data = response,
prevKey = null,
nextKey = null,
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
import nl.adaptivity.xmlutil.serialization.XML

internal object Rss {
internal object RssService {
private val xml by lazy {
XML {
defaultPolicy {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal sealed interface Feed {
val title: Text,
@XmlSerialName("updated")
@XmlElement(true)
val updated: String, // ISO-8601 datetime string
val updated: String?, // ISO-8601 datetime string
@XmlSerialName("author")
@XmlElement(true)
val authors: List<Person> = emptyList(),
Expand Down Expand Up @@ -89,8 +89,39 @@ internal sealed interface Feed {
@XmlSerialName("category")
@XmlElement(true)
val categories: List<Category> = emptyList(),
@XmlSerialName("group", prefix = "media", namespace = "http://search.yahoo.com/mrss/")
@XmlElement(true)
val media: Media? = null,
)

@Serializable
data class Media(
@XmlSerialName("title", prefix = "media")
@XmlElement(true)
val title: Text? = null,
@XmlSerialName("content", prefix = "media")
@XmlElement(true)
val content: Content? = null,
@XmlSerialName("thumbnail", prefix = "media")
@XmlElement(true)
val thumbnail: Content? = null,
@XmlSerialName("description", prefix = "media")
@XmlElement(true)
val description: Text? = null,
) {
@Serializable
data class Content(
@XmlElement(false)
val type: String? = null,
@XmlElement(false)
val url: String,
@XmlElement(false)
val width: Int? = null,
@XmlElement(false)
val height: Int? = null,
)
}

@Serializable
data class Person(
@XmlSerialName("name")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public data class UiTimeline internal constructor(
val itemType: String
get() =
buildString {
append(platformType.name)
// append(platformType.name)
if (topMessage != null) {
append("withTopMessage")
}
Expand All @@ -46,6 +46,10 @@ public data class UiTimeline internal constructor(
is ItemContent.UserList -> {
append("UserList")
}

is ItemContent.Feed -> {
append("Feed")
}
}
}
}
Expand All @@ -55,9 +59,10 @@ public data class UiTimeline internal constructor(

public data class Feed internal constructor(
val title: String,
val description: String,
val description: String?,
val url: String,
val image: String?,
val createdAt: UiDateTime?,
) : ItemContent {
override val itemKey: String
get() = "Feed_$url"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package dev.dimension.flare.ui.model.mapper

import com.fleeksoft.ksoup.Ksoup
import dev.dimension.flare.data.network.rss.model.Feed
import dev.dimension.flare.ui.model.UiTimeline
import dev.dimension.flare.ui.render.toUi
import kotlinx.datetime.Instant

internal fun Feed.render(): List<UiTimeline> =
when (this) {
is Feed.Atom -> renderAtom()
is Feed.Rss20 -> renderRss20()
}

private fun Feed.Atom.renderAtom(): List<UiTimeline> =
this.entries.map {
val descHtml =
it.content?.value?.let {
Ksoup.parse(it)
}
val img = descHtml?.select("img")?.firstOrNull()?.attr("src") ?: it.media?.thumbnail?.url
UiTimeline(
topMessage = null,
content =
UiTimeline.ItemContent.Feed(
title = it.title.value,
description = descHtml?.text(),
url = it.links.first().href,
image = img,
createdAt = it.published?.let { input -> runCatching { Instant.parse(input) }.getOrNull() }?.toUi(),
),
)
}

private fun Feed.Rss20.renderRss20(): List<UiTimeline> =
this.channel.items.map {
val descHtml =
it.description?.let {
Ksoup.parse(it)
}
val img = descHtml?.select("img")?.firstOrNull()
UiTimeline(
topMessage = null,
content =
UiTimeline.ItemContent.Feed(
title = it.title,
description = descHtml?.text(),
url = it.link,
image = img?.attr("src"),
createdAt = it.pubDate?.let { input -> runCatching { Instant.parse(input) }.getOrNull() }?.toUi(),
),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import dev.dimension.flare.data.network.rss.Rss
import dev.dimension.flare.data.network.rss.RssService
import dev.dimension.flare.ui.model.UiState
import dev.dimension.flare.ui.model.collectAsUiState
import dev.dimension.flare.ui.model.flatMap
Expand All @@ -28,7 +28,7 @@ public class CheckRssSourcePresenter : PresenterBase<CheckRssSourcePresenter.Sta
snapshotFlow { url }
.map {
runCatching {
Rss.fetch(it)
RssService.fetch(it)
}.fold(
onSuccess = {
UiState.Success(true) as UiState<Boolean>
Expand Down
Loading

0 comments on commit 71fd76f

Please sign in to comment.