-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement highlight activity bottom sheet (#254)
* Fix referencedEventAuthorId is always NULL * Cache all events from get_highlights endpoint and save highlight comments * Connect comments with highlights * Implement highlight joins on same content * Implement Highlight Activity bottom sheet * Render comments in the highlight activity bottom sheet * Tweak comment section paddings to align with action buttons * Skip partially expanded state in bottom sheet
- Loading branch information
Showing
21 changed files
with
599 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
...ain/kotlin/net/primal/android/articles/api/mediator/ArticleHighlightsResponseProcessor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package net.primal.android.articles.api.mediator | ||
|
||
import androidx.room.withTransaction | ||
import net.primal.android.articles.api.model.ArticleHighlightsResponse | ||
import net.primal.android.core.ext.asMapByKey | ||
import net.primal.android.db.PrimalDatabase | ||
import net.primal.android.highlights.utils.mapNotNullAsHighlightComments | ||
import net.primal.android.nostr.db.eventRelayHintsUpserter | ||
import net.primal.android.nostr.ext.asHighlightData | ||
import net.primal.android.nostr.ext.flatMapAsEventHintsPO | ||
import net.primal.android.nostr.ext.flatMapNotNullAsCdnResource | ||
import net.primal.android.nostr.ext.mapAsEventZapDO | ||
import net.primal.android.nostr.ext.mapAsProfileDataPO | ||
import net.primal.android.nostr.ext.mapNotNullAsEventStatsPO | ||
import net.primal.android.nostr.ext.parseAndMapPrimalLegendProfiles | ||
import net.primal.android.nostr.ext.parseAndMapPrimalPremiumInfo | ||
import net.primal.android.nostr.ext.parseAndMapPrimalUserNames | ||
|
||
suspend fun ArticleHighlightsResponse.persistToDatabaseAsTransaction(database: PrimalDatabase) { | ||
val cdnResources = this.cdnResources.flatMapNotNullAsCdnResource().asMapByKey { it.url } | ||
val eventHints = this.relayHints.flatMapAsEventHintsPO() | ||
|
||
val primalUserNames = this.primalUserNames.parseAndMapPrimalUserNames() | ||
val primalPremiumInfo = this.primalPremiumInfo.parseAndMapPrimalPremiumInfo() | ||
val primalLegendProfiles = this.legendProfiles.parseAndMapPrimalLegendProfiles() | ||
|
||
val profiles = this.profileMetadatas.mapAsProfileDataPO( | ||
cdnResources = cdnResources, | ||
primalUserNames = primalUserNames, | ||
primalPremiumInfo = primalPremiumInfo, | ||
primalLegendProfiles = primalLegendProfiles, | ||
) | ||
|
||
val highlights = this.highlights.map { it.asHighlightData() } | ||
val highlightComments = this.highlightComments.mapNotNullAsHighlightComments(highlights = highlights) | ||
|
||
val eventZaps = this.zaps.mapAsEventZapDO(profilesMap = profiles.associateBy { it.ownerId }) | ||
val eventStats = this.eventStats.mapNotNullAsEventStatsPO() | ||
|
||
database.withTransaction { | ||
database.profiles().insertOrUpdateAll(data = profiles) | ||
database.posts().upsertAll(data = highlightComments) | ||
database.eventStats().upsertAll(data = eventStats) | ||
database.eventZaps().upsertAll(data = eventZaps) | ||
database.highlights().upsertAll(data = highlights) | ||
|
||
val eventHintsDao = database.eventHints() | ||
val hintsMap = eventHints.associateBy { it.eventId } | ||
eventRelayHintsUpserter(dao = eventHintsDao, eventIds = eventHints.map { it.eventId }) { | ||
copy(relays = hintsMap[this.eventId]?.relays ?: emptyList()) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
app/src/main/kotlin/net/primal/android/highlights/db/Highlight.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package net.primal.android.highlights.db | ||
|
||
import androidx.room.Embedded | ||
import androidx.room.Relation | ||
import net.primal.android.notes.db.PostData | ||
import net.primal.android.notes.db.PostWithAuthorData | ||
import net.primal.android.profile.db.ProfileData | ||
|
||
data class Highlight( | ||
@Embedded | ||
val data: HighlightData, | ||
|
||
@Relation(entityColumn = "ownerId", parentColumn = "authorId") | ||
val author: ProfileData? = null, | ||
|
||
@Relation(entity = PostData::class, entityColumn = "replyToPostId", parentColumn = "highlightId") | ||
val comments: List<PostWithAuthorData> = emptyList(), | ||
) |
30 changes: 30 additions & 0 deletions
30
app/src/main/kotlin/net/primal/android/highlights/model/CommentUi.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package net.primal.android.highlights.model | ||
|
||
import java.time.Instant | ||
import net.primal.android.attachments.domain.CdnImage | ||
import net.primal.android.notes.db.PostWithAuthorData | ||
import net.primal.android.premium.legend.LegendaryCustomization | ||
import net.primal.android.premium.legend.asLegendaryCustomization | ||
|
||
data class CommentUi( | ||
val commentId: String, | ||
val authorId: String, | ||
val authorDisplayName: String?, | ||
val authorInternetIdentifier: String?, | ||
val authorLegendaryCustomization: LegendaryCustomization?, | ||
val authorCdnImage: CdnImage?, | ||
val content: String, | ||
val createdAt: Instant, | ||
) | ||
|
||
fun PostWithAuthorData.toCommentUi() = | ||
CommentUi( | ||
commentId = this.post.postId, | ||
authorId = this.author.ownerId, | ||
authorDisplayName = this.author.displayName, | ||
authorInternetIdentifier = this.author.internetIdentifier, | ||
authorLegendaryCustomization = this.author.primalPremiumInfo?.legendProfile?.asLegendaryCustomization(), | ||
authorCdnImage = this.author.avatarCdnImage, | ||
content = this.post.content, | ||
createdAt = Instant.ofEpochSecond(this.post.createdAt), | ||
) |
54 changes: 43 additions & 11 deletions
54
app/src/main/kotlin/net/primal/android/highlights/model/HighlightUi.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,58 @@ | ||
package net.primal.android.highlights.model | ||
|
||
import net.primal.android.highlights.db.HighlightData | ||
import net.primal.android.core.compose.profile.model.ProfileDetailsUi | ||
import net.primal.android.core.compose.profile.model.asProfileDetailsUi | ||
import net.primal.android.highlights.db.Highlight | ||
|
||
data class HighlightUi( | ||
val highlightId: String, | ||
val authorId: String, | ||
val author: ProfileDetailsUi?, | ||
val content: String, | ||
val context: String?, | ||
val alt: String?, | ||
val referencedEventATag: String?, | ||
val referencedEventAuthorId: String?, | ||
val createdAt: Long, | ||
val comments: List<CommentUi>, | ||
) | ||
|
||
fun HighlightData.asHighlightUi() = | ||
data class JoinedHighlightsUi( | ||
val highlightId: String, | ||
val authors: Set<ProfileDetailsUi>, | ||
val content: String, | ||
val comments: List<CommentUi>, | ||
) | ||
|
||
fun Highlight.asHighlightUi() = | ||
HighlightUi( | ||
highlightId = highlightId, | ||
authorId = authorId, | ||
content = content, | ||
context = context, | ||
alt = alt, | ||
referencedEventATag = referencedEventATag, | ||
referencedEventAuthorId = referencedEventAuthorId, | ||
createdAt = createdAt, | ||
highlightId = this.data.highlightId, | ||
author = this.author?.asProfileDetailsUi(), | ||
content = this.data.content, | ||
context = this.data.context, | ||
alt = this.data.alt, | ||
referencedEventATag = this.data.referencedEventATag, | ||
referencedEventAuthorId = this.data.referencedEventAuthorId, | ||
createdAt = this.data.createdAt, | ||
comments = this.comments.map { it.toCommentUi() }, | ||
) | ||
|
||
operator fun JoinedHighlightsUi.plus(element: JoinedHighlightsUi): JoinedHighlightsUi = | ||
JoinedHighlightsUi( | ||
highlightId = this.highlightId, | ||
authors = this.authors + element.authors, | ||
content = this.content, | ||
comments = this.comments + element.comments, | ||
) | ||
|
||
fun List<Highlight>.joinOnContent(): List<JoinedHighlightsUi> = this.groupBy { it.data.content }.map { it.value.sum() } | ||
|
||
fun List<Highlight>.sum() = | ||
this.map { it.asJoinedHighlightsUi() }.reduce { acc, joinedHighlightsUi -> acc + joinedHighlightsUi } | ||
|
||
fun Highlight.asJoinedHighlightsUi() = | ||
JoinedHighlightsUi( | ||
highlightId = this.data.highlightId, | ||
authors = setOfNotNull(this.author?.asProfileDetailsUi()), | ||
content = this.data.content, | ||
comments = this.comments.map { it.toCommentUi() }, | ||
) |
44 changes: 44 additions & 0 deletions
44
app/src/main/kotlin/net/primal/android/highlights/utils/HighlightCommentsUtils.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package net.primal.android.highlights.utils | ||
|
||
import kotlinx.serialization.encodeToString | ||
import kotlinx.serialization.json.JsonArray | ||
import net.primal.android.core.serialization.json.NostrJson | ||
import net.primal.android.core.serialization.json.toJsonObject | ||
import net.primal.android.core.utils.parseHashtags | ||
import net.primal.android.core.utils.parseUris | ||
import net.primal.android.highlights.db.HighlightData | ||
import net.primal.android.nostr.ext.getTagValueOrNull | ||
import net.primal.android.nostr.ext.hasReplyMarker | ||
import net.primal.android.nostr.ext.hasRootMarker | ||
import net.primal.android.nostr.ext.isEventIdTag | ||
import net.primal.android.nostr.model.NostrEvent | ||
import net.primal.android.notes.db.PostData | ||
|
||
fun List<NostrEvent>.mapNotNullAsHighlightComments(highlights: List<HighlightData>): List<PostData> = | ||
this.mapNotNull { it.asHighlightComment(highlights = highlights) } | ||
|
||
fun NostrEvent.asHighlightComment(highlights: List<HighlightData>): PostData? { | ||
if (!this.tags.containsRootOrReplyTag()) { | ||
return null | ||
} | ||
|
||
val replyToPostId = this.tags.find { it.isEventIdTag() }?.getTagValueOrNull() | ||
|
||
val replyToAuthorId = highlights.find { it.highlightId == replyToPostId }?.authorId | ||
|
||
return PostData( | ||
postId = this.id, | ||
authorId = this.pubKey, | ||
createdAt = this.createdAt, | ||
tags = this.tags, | ||
content = this.content, | ||
uris = this.content.parseUris(), | ||
hashtags = this.parseHashtags(), | ||
sig = this.sig, | ||
raw = NostrJson.encodeToString(this.toJsonObject()), | ||
replyToPostId = replyToPostId, | ||
replyToAuthorId = replyToAuthorId, | ||
) | ||
} | ||
|
||
fun List<JsonArray>.containsRootOrReplyTag() = this.any { it.hasRootMarker() || it.hasReplyMarker() } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.