Add ArtifactDetailScreen with chapters and translations
Clicking an artifact in a chat room's library now opens an artifact detail screen instead of the placeholder route. - New ArtifactDetailRoute + ArtifactDetailScreen/ViewModel/UIState. The screen shows the artifact's details (name, url, visibility, license, dialect, author, created), its versions, and — walked via the artifact's versions — the associated chapters and translations, each with an empty state. - DAO queries (validated by Room): getArtifactById, versions by artifactId, chapters by artifactId (Chapter JOIN ArtifactVersion, ordered by index), and translations by artifactId (TranslationArtifactVersion JOIN ArtifactVersion). Exposed via MantraRepository (impl + NO_OP). - ChatRoomDetailScreen navigates to ArtifactDetailRoute on artifact click; MantraNavHost registers the route with a back-stack pop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -12,4 +12,7 @@ interface MantraArtifactDao {
|
||||
|
||||
@Query("SELECT * FROM MantraArtifact WHERE chatRoomId = :chatRoomId ORDER BY createdAt DESC")
|
||||
suspend fun getArtifactsByChatRoomId(chatRoomId: String): List<MantraArtifact>
|
||||
|
||||
@Query("SELECT * FROM MantraArtifact WHERE id = :id")
|
||||
suspend fun getArtifactById(id: String): MantraArtifact?
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package press.mantra.compose.database.dao
|
||||
import androidx.room3.Dao
|
||||
import androidx.room3.Insert
|
||||
import androidx.room3.OnConflictStrategy.Companion.IGNORE
|
||||
import androidx.room3.Query
|
||||
import androidx.room3.Upsert
|
||||
import press.mantra.compose.database.model.MantraArtifactVersion
|
||||
|
||||
@@ -10,4 +11,7 @@ import press.mantra.compose.database.model.MantraArtifactVersion
|
||||
interface MantraArtifactVersionDao {
|
||||
@Upsert
|
||||
suspend fun upsert(mantraArtifactVersion: MantraArtifactVersion)
|
||||
|
||||
@Query("SELECT * FROM MantraArtifactVersion WHERE artifactId = :artifactId ORDER BY createdAt DESC")
|
||||
suspend fun getArtifactVersionsByArtifactId(artifactId: String): List<MantraArtifactVersion>
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package press.mantra.compose.database.dao
|
||||
import androidx.room3.Dao
|
||||
import androidx.room3.Insert
|
||||
import androidx.room3.OnConflictStrategy.Companion.IGNORE
|
||||
import androidx.room3.Query
|
||||
import androidx.room3.Upsert
|
||||
import press.mantra.compose.database.model.MantraChapter
|
||||
|
||||
@@ -10,4 +11,16 @@ import press.mantra.compose.database.model.MantraChapter
|
||||
interface MantraChapterDao {
|
||||
@Upsert
|
||||
suspend fun upsert(mantraChapter: MantraChapter)
|
||||
|
||||
/** Chapters across all versions of an artifact, ordered by their in-book index. */
|
||||
@Query(
|
||||
"""
|
||||
SELECT MantraChapter.* FROM MantraChapter
|
||||
INNER JOIN MantraArtifactVersion
|
||||
ON MantraChapter.artifactVersionId = MantraArtifactVersion.id
|
||||
WHERE MantraArtifactVersion.artifactId = :artifactId
|
||||
ORDER BY MantraChapter.`index` ASC
|
||||
"""
|
||||
)
|
||||
suspend fun getChaptersByArtifactId(artifactId: String): List<MantraChapter>
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package press.mantra.compose.database.dao
|
||||
import androidx.room3.Dao
|
||||
import androidx.room3.Insert
|
||||
import androidx.room3.OnConflictStrategy.Companion.IGNORE
|
||||
import androidx.room3.Query
|
||||
import androidx.room3.Upsert
|
||||
import press.mantra.compose.database.model.MantraTranslationArtifactVersion
|
||||
|
||||
@@ -10,4 +11,16 @@ import press.mantra.compose.database.model.MantraTranslationArtifactVersion
|
||||
interface MantraTranslationArtifactVersionDao {
|
||||
@Upsert
|
||||
suspend fun upsert(mantraTranslationArtifactVersion: MantraTranslationArtifactVersion)
|
||||
|
||||
/** Translations targeting any version of an artifact. */
|
||||
@Query(
|
||||
"""
|
||||
SELECT MantraTranslationArtifactVersion.* FROM MantraTranslationArtifactVersion
|
||||
INNER JOIN MantraArtifactVersion
|
||||
ON MantraTranslationArtifactVersion.artifactVersionId = MantraArtifactVersion.id
|
||||
WHERE MantraArtifactVersion.artifactId = :artifactId
|
||||
ORDER BY MantraTranslationArtifactVersion.createdAt DESC
|
||||
"""
|
||||
)
|
||||
suspend fun getTranslationsByArtifactId(artifactId: String): List<MantraTranslationArtifactVersion>
|
||||
}
|
||||
@@ -6,7 +6,9 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import press.mantra.compose.database.MantraDatabase
|
||||
import press.mantra.compose.database.model.MantraArtifact
|
||||
import press.mantra.compose.database.model.MantraArtifactVersion
|
||||
import press.mantra.compose.database.model.MantraChapter
|
||||
import press.mantra.compose.database.model.MantraDialect
|
||||
import press.mantra.compose.database.model.MantraTranslationArtifactVersion
|
||||
import press.mantra.compose.database.model.MarmotInnerEvent
|
||||
import press.mantra.compose.nostr.nip30303.ArtifactEvent
|
||||
import press.mantra.compose.nostr.nip30303.ArtifactVersionEvent
|
||||
@@ -24,6 +26,18 @@ class DatabaseMantraRepository(
|
||||
override suspend fun getArtifacts(chatRoomId: String): List<MantraArtifact> =
|
||||
database.mantraArtifactDao().getArtifactsByChatRoomId(chatRoomId)
|
||||
|
||||
override suspend fun getArtifact(id: String): MantraArtifact? =
|
||||
database.mantraArtifactDao().getArtifactById(id)
|
||||
|
||||
override suspend fun getArtifactVersions(artifactId: String): List<MantraArtifactVersion> =
|
||||
database.mantraArtifactVersionDao().getArtifactVersionsByArtifactId(artifactId)
|
||||
|
||||
override suspend fun getChaptersForArtifact(artifactId: String): List<MantraChapter> =
|
||||
database.mantraChapterDao().getChaptersByArtifactId(artifactId)
|
||||
|
||||
override suspend fun getTranslationsForArtifact(artifactId: String): List<MantraTranslationArtifactVersion> =
|
||||
database.mantraTranslationArtifactVersionDao().getTranslationsByArtifactId(artifactId)
|
||||
|
||||
override suspend fun getDialects(chatRoomId: String): List<MantraDialect> =
|
||||
database.mantraDialectDao().getDialectsByChatRoomId(chatRoomId)
|
||||
|
||||
|
||||
@@ -2,12 +2,23 @@ package press.mantra.compose.repository
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import press.mantra.compose.database.model.MantraArtifact
|
||||
import press.mantra.compose.database.model.MantraArtifactVersion
|
||||
import press.mantra.compose.database.model.MantraChapter
|
||||
import press.mantra.compose.database.model.MantraDialect
|
||||
import press.mantra.compose.database.model.MantraTranslationArtifactVersion
|
||||
import press.mantra.compose.database.model.MarmotInnerEvent
|
||||
|
||||
interface MantraRepository {
|
||||
suspend fun getArtifacts(chatRoomId: String): List<MantraArtifact>
|
||||
|
||||
suspend fun getArtifact(id: String): MantraArtifact?
|
||||
|
||||
suspend fun getArtifactVersions(artifactId: String): List<MantraArtifactVersion>
|
||||
|
||||
suspend fun getChaptersForArtifact(artifactId: String): List<MantraChapter>
|
||||
|
||||
suspend fun getTranslationsForArtifact(artifactId: String): List<MantraTranslationArtifactVersion>
|
||||
|
||||
suspend fun getDialects(chatRoomId: String): List<MantraDialect>
|
||||
|
||||
suspend fun addDialect(
|
||||
@@ -43,6 +54,14 @@ interface MantraRepository {
|
||||
val NO_OP_MANTRA_REPOSITORY = object: MantraRepository{
|
||||
override suspend fun getArtifacts(chatRoomId: String): List<MantraArtifact> = emptyList()
|
||||
|
||||
override suspend fun getArtifact(id: String): MantraArtifact? = null
|
||||
|
||||
override suspend fun getArtifactVersions(artifactId: String): List<MantraArtifactVersion> = emptyList()
|
||||
|
||||
override suspend fun getChaptersForArtifact(artifactId: String): List<MantraChapter> = emptyList()
|
||||
|
||||
override suspend fun getTranslationsForArtifact(artifactId: String): List<MantraTranslationArtifactVersion> = emptyList()
|
||||
|
||||
override suspend fun getDialects(chatRoomId: String): List<MantraDialect> = emptyList()
|
||||
|
||||
override suspend fun addDialect(
|
||||
|
||||
@@ -0,0 +1,268 @@
|
||||
package press.mantra.compose.ui.composable
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Article
|
||||
import androidx.compose.material.icons.filled.Translate
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import press.mantra.compose.database.model.MantraArtifact
|
||||
import press.mantra.compose.repository.MantraRepository
|
||||
import press.mantra.compose.ui.composable.widgets.LoadingDataIndicator
|
||||
import press.mantra.compose.ui.theme.TorchTheme
|
||||
import press.mantra.compose.ui.view.model.ArtifactDetailViewModel
|
||||
import press.mantra.compose.ui.view.state.ArtifactDetailUIState
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ArtifactDetailScreen(
|
||||
activeUserPublicKey: HexKey,
|
||||
artifactId: String,
|
||||
chatRoomId: String,
|
||||
relayHint: String?,
|
||||
initialArtifactDetailUIState: ArtifactDetailUIState = ArtifactDetailUIState.Loading,
|
||||
mantraRepository: MantraRepository,
|
||||
onNavigateBack: () -> Unit,
|
||||
) {
|
||||
val artifactDetailViewModel: ArtifactDetailViewModel = viewModel(
|
||||
factory = ArtifactDetailViewModel.factory(
|
||||
activeUserPublicKey = activeUserPublicKey,
|
||||
artifactId = artifactId,
|
||||
chatRoomId = chatRoomId,
|
||||
relayHint = relayHint,
|
||||
initialArtifactDetailUIState = initialArtifactDetailUIState,
|
||||
mantraRepository = mantraRepository,
|
||||
)
|
||||
)
|
||||
|
||||
when (val artifactDetailUIState = artifactDetailViewModel.artifactDetailUIState) {
|
||||
is ArtifactDetailUIState.Error -> {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(50.dp))
|
||||
Text(text = artifactDetailUIState.message)
|
||||
}
|
||||
}
|
||||
|
||||
is ArtifactDetailUIState.Loaded -> {
|
||||
val artifact = artifactDetailUIState.artifact
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text(artifact.name) },
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onNavigateBack) {
|
||||
Icon(
|
||||
Icons.AutoMirrored.Filled.ArrowBack,
|
||||
contentDescription = "Back"
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
) { innerPadding ->
|
||||
LazyColumn(
|
||||
modifier = Modifier.padding(innerPadding).fillMaxSize().padding(20.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp)
|
||||
) {
|
||||
// Details
|
||||
item {
|
||||
Text(
|
||||
text = "Details",
|
||||
style = MaterialTheme.typography.labelMedium
|
||||
)
|
||||
}
|
||||
item {
|
||||
Card {
|
||||
DetailRow(label = "Name", value = artifact.name)
|
||||
DetailRow(label = "Url", value = artifact.url)
|
||||
DetailRow(label = "Visibility", value = artifact.visibility)
|
||||
DetailRow(label = "License", value = artifact.license)
|
||||
DetailRow(label = "Dialect", value = artifact.dialectId)
|
||||
DetailRow(label = "Author", value = artifact.publicKey)
|
||||
DetailRow(label = "Created", value = artifact.createdAt.toString())
|
||||
}
|
||||
}
|
||||
|
||||
// Versions
|
||||
item {
|
||||
Text(
|
||||
text = "Versions",
|
||||
style = MaterialTheme.typography.labelMedium
|
||||
)
|
||||
}
|
||||
if (artifactDetailUIState.versions.isEmpty()) {
|
||||
item { Text("No versions.") }
|
||||
} else {
|
||||
items(
|
||||
items = artifactDetailUIState.versions,
|
||||
key = { version -> version.id }
|
||||
) { version ->
|
||||
Card {
|
||||
ListItem(
|
||||
headlineContent = { Text(version.versionLabel) },
|
||||
overlineContent = { Text("Version") }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item { HorizontalDivider() }
|
||||
|
||||
// Chapters
|
||||
item {
|
||||
Text(
|
||||
text = "Chapters",
|
||||
style = MaterialTheme.typography.labelMedium
|
||||
)
|
||||
}
|
||||
if (artifactDetailUIState.chapters.isEmpty()) {
|
||||
item { Text("No chapters yet.") }
|
||||
} else {
|
||||
items(
|
||||
items = artifactDetailUIState.chapters,
|
||||
key = { chapter -> chapter.id }
|
||||
) { chapter ->
|
||||
Card {
|
||||
ListItem(
|
||||
leadingContent = {
|
||||
Icon(
|
||||
Icons.Default.Article,
|
||||
contentDescription = "Chapter"
|
||||
)
|
||||
},
|
||||
overlineContent = { Text("Chapter ${chapter.index}") },
|
||||
headlineContent = { Text(chapter.name) },
|
||||
supportingContent = {
|
||||
Text("${chapter.wordCount} words · ${chapter.characterCount} characters")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item { HorizontalDivider() }
|
||||
|
||||
// Translations
|
||||
item {
|
||||
Text(
|
||||
text = "Translations",
|
||||
style = MaterialTheme.typography.labelMedium
|
||||
)
|
||||
}
|
||||
if (artifactDetailUIState.translations.isEmpty()) {
|
||||
item { Text("No translations yet.") }
|
||||
} else {
|
||||
items(
|
||||
items = artifactDetailUIState.translations,
|
||||
key = { translation -> translation.id }
|
||||
) { translation ->
|
||||
Card {
|
||||
ListItem(
|
||||
leadingContent = {
|
||||
Icon(
|
||||
Icons.Default.Translate,
|
||||
contentDescription = "Translation"
|
||||
)
|
||||
},
|
||||
headlineContent = { Text(translation.name) },
|
||||
supportingContent = { Text(translation.visibility) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArtifactDetailUIState.Loading -> {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth().padding(20.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(20.dp)
|
||||
) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Text(
|
||||
text = "Artifact Detail",
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
LoadingDataIndicator(fillScreen = false)
|
||||
Spacer(modifier = Modifier.weight(2f))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(true) {
|
||||
if (initialArtifactDetailUIState == ArtifactDetailUIState.Loading) {
|
||||
artifactDetailViewModel.initiateArtifactDetail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DetailRow(label: String, value: String) {
|
||||
ListItem(
|
||||
overlineContent = { Text(label) },
|
||||
headlineContent = { Text(value) }
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun ArtifactDetailScreenPreview() {
|
||||
TorchTheme {
|
||||
Surface(modifier = Modifier.fillMaxSize()) {
|
||||
ArtifactDetailScreen(
|
||||
activeUserPublicKey = "",
|
||||
artifactId = "artifactId",
|
||||
chatRoomId = "chatRoomId",
|
||||
relayHint = null,
|
||||
initialArtifactDetailUIState = ArtifactDetailUIState.Loaded(
|
||||
artifact = MantraArtifact(
|
||||
id = "artifactId",
|
||||
publicKey = "author",
|
||||
name = "To Kill a Mockingbird",
|
||||
url = "https://harper.com/2-kill-Bird",
|
||||
visibility = "private",
|
||||
dialectId = "dialectId",
|
||||
license = "cc",
|
||||
chatRoomId = "chatRoomId",
|
||||
signature = ""
|
||||
)
|
||||
),
|
||||
mantraRepository = MantraRepository.NO_OP_MANTRA_REPOSITORY,
|
||||
onNavigateBack = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,7 @@ import press.mantra.compose.ui.view.model.ChatRoomDetailViewModel
|
||||
import press.mantra.compose.ui.view.state.ChatRoomDetailUIState
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import press.mantra.compose.ui.composable.navigation.routes.AddArtifactRoute
|
||||
import press.mantra.compose.ui.composable.navigation.routes.ArtifactDetailRoute
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@@ -150,8 +151,11 @@ fun ChatRoomDetailScreen(
|
||||
Card(
|
||||
onClick = {
|
||||
onNavigateToRoute.invoke(
|
||||
ImplementationPendingRoute(
|
||||
"Artifact detail"
|
||||
ArtifactDetailRoute(
|
||||
activeUserPublicKey = activeUserPublicKey,
|
||||
artifactId = artifact.id,
|
||||
chatRoomId = chatRoomId,
|
||||
relayHint = relayHint
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -89,6 +89,8 @@ import kotlinx.coroutines.launch
|
||||
import press.mantra.compose.database.repository.DatabaseMantraRepository
|
||||
import press.mantra.compose.ui.composable.AddArtifactScreen
|
||||
import press.mantra.compose.ui.composable.navigation.routes.AddArtifactRoute
|
||||
import press.mantra.compose.ui.composable.navigation.routes.ArtifactDetailRoute
|
||||
import press.mantra.compose.ui.composable.ArtifactDetailScreen
|
||||
|
||||
@Composable
|
||||
fun MantraNavHost(
|
||||
@@ -675,6 +677,20 @@ fun MantraNavHost(
|
||||
}
|
||||
)
|
||||
}
|
||||
composable<ArtifactDetailRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<ArtifactDetailRoute>()
|
||||
|
||||
ArtifactDetailScreen(
|
||||
activeUserPublicKey = route.activeUserPublicKey,
|
||||
artifactId = route.artifactId,
|
||||
chatRoomId = route.chatRoomId,
|
||||
relayHint = route.relayHint,
|
||||
mantraRepository = databaseMantraRepository,
|
||||
onNavigateBack = {
|
||||
navController.popBackStack()
|
||||
}
|
||||
)
|
||||
}
|
||||
composable<SearchRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<SearchRoute>()
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package press.mantra.compose.ui.composable.navigation.routes
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ArtifactDetailRoute(
|
||||
val activeUserPublicKey: String,
|
||||
val artifactId: String,
|
||||
val chatRoomId: String,
|
||||
val relayHint: String?
|
||||
): Route()
|
||||
@@ -0,0 +1,74 @@
|
||||
package press.mantra.compose.ui.view.model
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import co.touchlab.kermit.Logger
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.IO
|
||||
import kotlinx.coroutines.launch
|
||||
import press.mantra.compose.repository.MantraRepository
|
||||
import press.mantra.compose.ui.view.state.ArtifactDetailUIState
|
||||
|
||||
class ArtifactDetailViewModel(
|
||||
val artifactId: String,
|
||||
val chatRoomId: String,
|
||||
val activeUserPublicKey: HexKey,
|
||||
val relayHint: String?,
|
||||
initialArtifactDetailUIState: ArtifactDetailUIState,
|
||||
val mantraRepository: MantraRepository,
|
||||
): ViewModel() {
|
||||
|
||||
var artifactDetailUIState: ArtifactDetailUIState by mutableStateOf(initialArtifactDetailUIState)
|
||||
private set
|
||||
|
||||
private val logger = Logger.withTag(TAG)
|
||||
|
||||
fun initiateArtifactDetail() {
|
||||
logger.d("initiateArtifactDetail: $artifactId")
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val artifact = mantraRepository.getArtifact(artifactId)
|
||||
|
||||
artifactDetailUIState = if (artifact == null) {
|
||||
ArtifactDetailUIState.Error("Couldn't find the artifact")
|
||||
} else {
|
||||
ArtifactDetailUIState.Loaded(
|
||||
artifact = artifact,
|
||||
versions = mantraRepository.getArtifactVersions(artifactId),
|
||||
chapters = mantraRepository.getChaptersForArtifact(artifactId),
|
||||
translations = mantraRepository.getTranslationsForArtifact(artifactId),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "ArtifactDetailViewModel"
|
||||
|
||||
fun factory(
|
||||
activeUserPublicKey: HexKey,
|
||||
artifactId: String,
|
||||
chatRoomId: String,
|
||||
relayHint: String?,
|
||||
initialArtifactDetailUIState: ArtifactDetailUIState = ArtifactDetailUIState.Loading,
|
||||
mantraRepository: MantraRepository,
|
||||
): ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
ArtifactDetailViewModel(
|
||||
activeUserPublicKey = activeUserPublicKey,
|
||||
artifactId = artifactId,
|
||||
chatRoomId = chatRoomId,
|
||||
relayHint = relayHint,
|
||||
initialArtifactDetailUIState = initialArtifactDetailUIState,
|
||||
mantraRepository = mantraRepository,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package press.mantra.compose.ui.view.state
|
||||
|
||||
import press.mantra.compose.database.model.MantraArtifact
|
||||
import press.mantra.compose.database.model.MantraArtifactVersion
|
||||
import press.mantra.compose.database.model.MantraChapter
|
||||
import press.mantra.compose.database.model.MantraTranslationArtifactVersion
|
||||
|
||||
sealed interface ArtifactDetailUIState {
|
||||
data class Loaded(
|
||||
val artifact: MantraArtifact,
|
||||
val versions: List<MantraArtifactVersion> = emptyList(),
|
||||
val chapters: List<MantraChapter> = emptyList(),
|
||||
val translations: List<MantraTranslationArtifactVersion> = emptyList(),
|
||||
): ArtifactDetailUIState
|
||||
|
||||
data class Error(
|
||||
val message: String
|
||||
): ArtifactDetailUIState
|
||||
|
||||
data object Loading: ArtifactDetailUIState
|
||||
}
|
||||
Reference in New Issue
Block a user