1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
package dev.serrahima.lluerna.domain
/**
* the protocol-neutral domain model.
*
* nothing in here knows about `site.standard.*` (or any other lexicon). the
* source adapters map raw records into these types; the ui renders these types.
* that boundary is what makes a future bluesky/wafrn adapter additive.
*
* this is a starter: it will grow as we build the feed.
*/
/** which protocol a piece of content came from. */
enum class Protocol { STANDARD_SITE }
/** a publication (ours) or a foreign actor, depending on [protocol]. */
data class Author(
/** did, or an at-uri for a publication. */
val id: String,
/** a handle or publication slug, if known. */
val handle: String? = null,
val name: String,
val avatarUrl: String? = null,
/** canonical web url, if the author has one. */
val url: String? = null,
val protocol: Protocol = Protocol.STANDARD_SITE,
)
/**
* a post body is a sum type: either our rich native content, or opaque foreign
* content we can only render textually (a future bluesky/wafrn post).
*/
sealed interface PostBody {
data class Native(val blocks: List<Block>) : PostBody
data class Foreign(val text: String, val facets: List<Facet> = emptyList()) : PostBody
}
/** a block of native rich content. will grow (images, embeds, ...). */
sealed interface Block {
data class Paragraph(val text: String, val facets: List<Facet> = emptyList()) : Block
data class Header(val level: Int, val text: String) : Block
}
/** an inline annotation over a byte range of a text. */
sealed interface Facet {
val byteStart: Int
val byteEnd: Int
data class Link(override val byteStart: Int, override val byteEnd: Int, val uri: String) : Facet
data class Mention(override val byteStart: Int, override val byteEnd: Int, val uri: String) : Facet
data class Bold(override val byteStart: Int, override val byteEnd: Int) : Facet
data class Italic(override val byteStart: Int, override val byteEnd: Int) : Facet
data class Header(override val byteStart: Int, override val byteEnd: Int, val level: Int) : Facet
}
/**
* a post in the feed. [parents] is the chain toward the root, newest-nearest
* first; the tumblr dedup + "tags from every post in the chain" logic both
* operate on it.
*/
data class Post(
val uri: String,
val cid: String,
val author: Author,
val body: PostBody,
/** plaintext fallback (site.standard.document.textContent). */
val plaintext: String,
val tags: List<String> = emptyList(),
val publishedAt: Long,
val updatedAt: Long? = null,
val parents: List<Post> = emptyList(),
/** at-uri of the post this is an addition to, if it is a reblog-with-addition. */
val replyTarget: String? = null,
)
|