feat: let a group define the dialects it translates into
Dialects existed but had nowhere to come from. The only way to create
one was the "New dialect" branch buried inside the add-artifact form,
which meant a dialect could only be born as a side effect of adding the
first artifact written in it. A group that wanted to line up the
languages it works in before any source material arrived had no way to
say so, and a dialect created that way was invisible afterwards -- there
was no screen anywhere that listed what the group had defined.
Give the group detail screen a Dialects section between Library and
Projects: the dialects defined in this room, each showing its name over
"<language> · <country>", and an Add Dialect button. The cards do not
navigate -- there is no dialect detail screen to open, and a card that
goes nowhere is worse than one that plainly does not.
The add screen is the add-artifact form with the artifact half removed:
the same chat-room title bar, the same bottom bar with an extended FAB,
the same three fields (name, country, language) styled the same way.
On success it returns to the group with popUpTo<ChatRoomDetailRoute>
{inclusive = true}, replacing the stale detail screen beneath it so the
new dialect is actually in the list when you land -- these lists load
once, in the view model's initiate().
One deliberate difference from AddArtifactViewModel: it wraps its whole
body in `localChatRoom.chatRoom.toMlsGroup()?.let { ... }` and so does
nothing at all, silently, in a NIP-17 room. Nothing under
MantraRepository.addDialect needs an MLS group, so the gate is left out
rather than copied into a new screen as a button that does nothing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,309 @@
|
||||
package press.mantra.compose.ui.composable
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
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.text.input.rememberTextFieldState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Public
|
||||
import androidx.compose.material.icons.filled.Title
|
||||
import androidx.compose.material.icons.filled.Translate
|
||||
import androidx.compose.material3.BottomAppBar
|
||||
import androidx.compose.material3.BottomAppBarDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
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.graphics.Color
|
||||
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.ChatRoom
|
||||
import press.mantra.compose.database.model.intermdiate.LocalChatRoom
|
||||
import press.mantra.compose.repository.ChatRepository
|
||||
import press.mantra.compose.repository.MantraRepository
|
||||
import press.mantra.compose.repository.NostrRepository
|
||||
import press.mantra.compose.ui.composable.navigation.routes.ChatRoomDetailRoute
|
||||
import press.mantra.compose.ui.composable.navigation.routes.ImplementationPendingRoute
|
||||
import press.mantra.compose.ui.composable.navigation.routes.Route
|
||||
import press.mantra.compose.ui.composable.widgets.LoadingDataIndicator
|
||||
import press.mantra.compose.ui.theme.TorchTheme
|
||||
import press.mantra.compose.ui.view.model.AddDialectViewModel
|
||||
import press.mantra.compose.ui.view.state.AddDialectUIState
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AddDialectScreen(
|
||||
activeUserPublicKey: HexKey,
|
||||
chatRoomId: String,
|
||||
relayHint: String?,
|
||||
initialAddDialectUIState: AddDialectUIState = AddDialectUIState.Loading,
|
||||
nostrRepository: NostrRepository,
|
||||
chatRepository: ChatRepository,
|
||||
mantraRepository: MantraRepository,
|
||||
onNavigateToRouteAndPopUpInclusive: (Route) -> Unit,
|
||||
onNavigateToRoute: (Route) -> Unit,
|
||||
) {
|
||||
val addDialectViewModel: AddDialectViewModel = viewModel(
|
||||
factory = AddDialectViewModel.factory(
|
||||
chatRoomId = chatRoomId,
|
||||
relayHint = relayHint,
|
||||
initialAddDialectUIState = initialAddDialectUIState,
|
||||
nostrRepository = nostrRepository,
|
||||
chatRepository = chatRepository,
|
||||
activeUserPublicKey = activeUserPublicKey,
|
||||
mantraRepository = mantraRepository
|
||||
)
|
||||
)
|
||||
|
||||
when (val addDialectUIState = addDialectViewModel.addDialectUIState) {
|
||||
is AddDialectUIState.Error -> {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Spacer(
|
||||
modifier = Modifier.height(50.dp)
|
||||
)
|
||||
Text(
|
||||
text = addDialectUIState.message,
|
||||
)
|
||||
}
|
||||
}
|
||||
is AddDialectUIState.Loaded -> {
|
||||
val nameFieldState = rememberTextFieldState()
|
||||
val countryFieldState = rememberTextFieldState()
|
||||
val languageFieldState = rememberTextFieldState()
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
addDialectUIState.localChatRoom.RenderChatRoomTitleText()
|
||||
},
|
||||
actions = {
|
||||
|
||||
}
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
BottomAppBar(
|
||||
actions = {},
|
||||
floatingActionButton = {
|
||||
ExtendedFloatingActionButton(
|
||||
onClick = {
|
||||
addDialectViewModel.addDialect(
|
||||
localChatRoom = addDialectUIState.localChatRoom,
|
||||
nameField = nameFieldState,
|
||||
countryField = countryFieldState,
|
||||
languageField = languageFieldState,
|
||||
onSuccess = {
|
||||
// Back to the group, reloaded so the new
|
||||
// dialect shows up in the list.
|
||||
onNavigateToRouteAndPopUpInclusive.invoke(
|
||||
ChatRoomDetailRoute(
|
||||
activeUserPublicKey = activeUserPublicKey,
|
||||
chatRoomId = chatRoomId,
|
||||
relayHint = relayHint
|
||||
)
|
||||
)
|
||||
},
|
||||
onFailure = {
|
||||
onNavigateToRoute.invoke(
|
||||
ImplementationPendingRoute("Failed Dialect")
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Add,
|
||||
contentDescription = "Add dialect"
|
||||
)
|
||||
Text("Add Dialect")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
) { innerPadding ->
|
||||
Column(
|
||||
modifier = Modifier.padding(innerPadding).fillMaxSize()
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text("Add a dialect the group can translate into")
|
||||
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.background(BottomAppBarDefaults.containerColor),
|
||||
state = nameFieldState,
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
focusedBorderColor = Color.Transparent,
|
||||
unfocusedBorderColor = Color.Transparent,
|
||||
disabledBorderColor = Color.Transparent
|
||||
),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Default.Title,
|
||||
contentDescription = "Name of the dialect"
|
||||
)
|
||||
},
|
||||
label = {
|
||||
Text(
|
||||
text = "Dialect Name"
|
||||
)
|
||||
},
|
||||
placeholder = {
|
||||
Text(
|
||||
text = "eg. Sesotho"
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.background(BottomAppBarDefaults.containerColor),
|
||||
state = countryFieldState,
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
focusedBorderColor = Color.Transparent,
|
||||
unfocusedBorderColor = Color.Transparent,
|
||||
disabledBorderColor = Color.Transparent
|
||||
),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Default.Public,
|
||||
contentDescription = "Country of the dialect"
|
||||
)
|
||||
},
|
||||
label = {
|
||||
Text(
|
||||
text = "Country"
|
||||
)
|
||||
},
|
||||
placeholder = {
|
||||
Text(
|
||||
text = "eg. Lesotho"
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.background(BottomAppBarDefaults.containerColor),
|
||||
state = languageFieldState,
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
focusedBorderColor = Color.Transparent,
|
||||
unfocusedBorderColor = Color.Transparent,
|
||||
disabledBorderColor = Color.Transparent
|
||||
),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Default.Translate,
|
||||
contentDescription = "Language of the dialect"
|
||||
)
|
||||
},
|
||||
label = {
|
||||
Text(
|
||||
text = "Language"
|
||||
)
|
||||
},
|
||||
placeholder = {
|
||||
Text(
|
||||
text = "eg. st"
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AddDialectUIState.Loading -> {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth().padding(
|
||||
20.dp
|
||||
),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(20.dp)
|
||||
) {
|
||||
|
||||
Spacer(
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Text(
|
||||
text = "Add Dialect",
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
LoadingDataIndicator(
|
||||
fillScreen = false
|
||||
)
|
||||
|
||||
Spacer(
|
||||
modifier = Modifier.weight(2f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(true) {
|
||||
if (initialAddDialectUIState == AddDialectUIState.Loading) {
|
||||
addDialectViewModel.initiateAddDialect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun AddDialectScreenPreview() {
|
||||
TorchTheme {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
AddDialectScreen(
|
||||
activeUserPublicKey = "",
|
||||
chatRoomId = "publicKey",
|
||||
relayHint = null,
|
||||
initialAddDialectUIState = AddDialectUIState.Loaded(
|
||||
localChatRoom = LocalChatRoom(
|
||||
chatRoom = ChatRoom(
|
||||
id = "",
|
||||
userPublicKey = "",
|
||||
subject = "Message title",
|
||||
description = "See something. Say somethin",
|
||||
initialGiftWrapPayloadId = "sdfaer",
|
||||
mlsGroupState = null
|
||||
),
|
||||
)
|
||||
),
|
||||
nostrRepository = NostrRepository.NO_OP_NOSTR_REPOSITORY,
|
||||
chatRepository = ChatRepository.NO_OP_CHAT_REPOSITORY,
|
||||
mantraRepository = MantraRepository.NO_OP_MANTRA_REPOSITORY,
|
||||
onNavigateToRouteAndPopUpInclusive = {},
|
||||
onNavigateToRoute = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import androidx.compose.material.icons.filled.DeleteForever
|
||||
import androidx.compose.material.icons.filled.LibraryBooks
|
||||
import androidx.compose.material.icons.filled.PersonAdd
|
||||
import androidx.compose.material.icons.filled.Schema
|
||||
import androidx.compose.material.icons.filled.Translate
|
||||
import androidx.compose.material.icons.filled.Unsubscribe
|
||||
import androidx.compose.material.icons.filled.WaterfallChart
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
@@ -60,6 +61,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.AddDialectRoute
|
||||
import press.mantra.compose.ui.composable.navigation.routes.ArtifactDetailRoute
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
|
||||
@@ -217,6 +219,72 @@ fun ChatRoomDetailScreen(
|
||||
HorizontalDivider()
|
||||
}
|
||||
|
||||
item {
|
||||
// Dialects
|
||||
Text(
|
||||
text = "Dialects",
|
||||
style = MaterialTheme.typography.labelMedium
|
||||
)
|
||||
}
|
||||
|
||||
if (chatRoomDetailUIState.dialects.isEmpty()) {
|
||||
item {
|
||||
Text("No dialects have been defined in this group.")
|
||||
}
|
||||
} else {
|
||||
items(
|
||||
items = chatRoomDetailUIState.dialects,
|
||||
key = { dialect -> dialect.id }
|
||||
) { dialect ->
|
||||
Card {
|
||||
ListItem(
|
||||
leadingContent = {
|
||||
Icon(
|
||||
Icons.Default.Translate,
|
||||
contentDescription = "Dialect"
|
||||
)
|
||||
},
|
||||
headlineContent = {
|
||||
Text(text = dialect.name)
|
||||
},
|
||||
supportingContent = {
|
||||
Text(text = "${dialect.language} \u00b7 ${dialect.country}")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onNavigateToRoute.invoke(
|
||||
AddDialectRoute(
|
||||
chatRoomId = chatRoomId,
|
||||
activeUserPublicKey = activeUserPublicKey,
|
||||
relayHint = relayHint
|
||||
)
|
||||
)
|
||||
}
|
||||
) {
|
||||
|
||||
Icon(
|
||||
Icons.Default.Translate,
|
||||
contentDescription = "Add new dialect"
|
||||
)
|
||||
|
||||
Spacer(
|
||||
modifier = Modifier.width(10.dp)
|
||||
)
|
||||
|
||||
Text("Add Dialect")
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
HorizontalDivider()
|
||||
}
|
||||
|
||||
// TODO: Add projects...
|
||||
|
||||
item {
|
||||
|
||||
@@ -103,6 +103,7 @@ 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.AddDialectRoute
|
||||
import press.mantra.compose.ui.composable.navigation.routes.AddChapterRoute
|
||||
import press.mantra.compose.ui.composable.navigation.routes.AddTranslationRoute
|
||||
import press.mantra.compose.ui.composable.navigation.routes.ArtifactDetailRoute
|
||||
@@ -112,6 +113,7 @@ import press.mantra.compose.ui.composable.navigation.routes.TranslationChapterRo
|
||||
import press.mantra.compose.ui.composable.navigation.routes.TranslationArtifactVersionDetailRoute
|
||||
import press.mantra.compose.ui.composable.ArtifactDetailScreen
|
||||
import press.mantra.compose.ui.composable.AddChapterScreen
|
||||
import press.mantra.compose.ui.composable.AddDialectScreen
|
||||
import press.mantra.compose.ui.composable.AddTranslationArtifactVersionScreen
|
||||
import press.mantra.compose.ui.composable.ChapterDetailScreen
|
||||
import press.mantra.compose.ui.composable.TranslateChunkScreen
|
||||
@@ -814,6 +816,34 @@ fun MantraNavHost(
|
||||
}
|
||||
)
|
||||
}
|
||||
composable<AddDialectRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<AddDialectRoute>()
|
||||
|
||||
AddDialectScreen(
|
||||
activeUserPublicKey = route.activeUserPublicKey,
|
||||
chatRoomId = route.chatRoomId,
|
||||
relayHint = route.relayHint,
|
||||
nostrRepository = databaseNostrRepository,
|
||||
chatRepository = databaseChatRepository,
|
||||
mantraRepository = databaseMantraRepository,
|
||||
onNavigateToRouteAndPopUpInclusive = { chatRoomDetailRoute ->
|
||||
// Replace both this add screen and the stale chat room detail
|
||||
// beneath it so we land on a freshly-loaded detail screen.
|
||||
navController.navigate(
|
||||
route = chatRoomDetailRoute
|
||||
) {
|
||||
popUpTo<ChatRoomDetailRoute> {
|
||||
inclusive = true
|
||||
}
|
||||
}
|
||||
},
|
||||
onNavigateToRoute = { actionRoute ->
|
||||
navController.navigate(
|
||||
route = actionRoute
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
composable<ArtifactDetailRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<ArtifactDetailRoute>()
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package press.mantra.compose.ui.composable.navigation.routes
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class AddDialectRoute(
|
||||
val activeUserPublicKey: String,
|
||||
val chatRoomId: String, // TODO: have this as a publicKey
|
||||
val relayHint: String?
|
||||
): Route()
|
||||
@@ -0,0 +1,134 @@
|
||||
package press.mantra.compose.ui.view.model
|
||||
|
||||
import androidx.compose.foundation.text.input.TextFieldState
|
||||
import androidx.compose.foundation.text.input.clearText
|
||||
import androidx.compose.runtime.MutableState
|
||||
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.database.model.intermdiate.LocalChatRoom
|
||||
import press.mantra.compose.repository.ChatRepository
|
||||
import press.mantra.compose.repository.MantraRepository
|
||||
import press.mantra.compose.repository.NostrRepository
|
||||
import press.mantra.compose.ui.view.state.AddDialectUIState
|
||||
|
||||
class AddDialectViewModel(
|
||||
val chatRoomId: String,
|
||||
val activeUserPublicKey: HexKey,
|
||||
val relayHint: String?,
|
||||
initialAddDialectUIState: AddDialectUIState,
|
||||
val nostrRepository: NostrRepository,
|
||||
val chatRepository: ChatRepository,
|
||||
val mantraRepository: MantraRepository,
|
||||
): ViewModel() {
|
||||
|
||||
var addDialectUIState: AddDialectUIState by mutableStateOf(initialAddDialectUIState)
|
||||
private set
|
||||
|
||||
private val logger = Logger.withTag(TAG)
|
||||
|
||||
val isActionPending: MutableState<Boolean> = mutableStateOf(false)
|
||||
|
||||
fun initiateAddDialect() {
|
||||
logger.d("compressed (most likely chat room): $chatRoomId")
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val localChatRoom = chatRepository.getChatRoomByIdentifier(chatRoomId)
|
||||
|
||||
addDialectUIState = if (localChatRoom == null) {
|
||||
AddDialectUIState.Error("Couldn't find the chat room")
|
||||
} else {
|
||||
AddDialectUIState.Loaded(
|
||||
localChatRoom = localChatRoom,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addDialect(
|
||||
localChatRoom: LocalChatRoom,
|
||||
nameField: TextFieldState,
|
||||
countryField: TextFieldState,
|
||||
languageField: TextFieldState,
|
||||
onSuccess: (dialectId: String) -> Unit,
|
||||
onFailure: () -> Unit
|
||||
) {
|
||||
val name = nameField.text.toString()
|
||||
val country = countryField.text.toString()
|
||||
val language = languageField.text.toString()
|
||||
|
||||
if (name.isBlank() || country.isBlank() || language.isBlank()) {
|
||||
onFailure.invoke()
|
||||
return
|
||||
}
|
||||
|
||||
// Guard against double submits from repeated FAB taps.
|
||||
if (isActionPending.value) return
|
||||
isActionPending.value = true
|
||||
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val dialectInnerEvent = runCatching {
|
||||
mantraRepository.addDialect(
|
||||
localChatRoom = localChatRoom,
|
||||
name = name,
|
||||
country = country,
|
||||
language = language,
|
||||
userPublicKey = activeUserPublicKey,
|
||||
)
|
||||
}.onFailure { error ->
|
||||
logger.e("Failed to add dialect", error)
|
||||
}.getOrNull()
|
||||
|
||||
if (dialectInnerEvent != null) {
|
||||
nameField.clearText()
|
||||
countryField.clearText()
|
||||
languageField.clearText()
|
||||
|
||||
viewModelScope.launch(Dispatchers.Main) {
|
||||
onSuccess.invoke(dialectInnerEvent.id)
|
||||
}
|
||||
} else {
|
||||
viewModelScope.launch(Dispatchers.Main) {
|
||||
onFailure.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
isActionPending.value = false
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "AddDialectViewModel"
|
||||
|
||||
fun factory(
|
||||
activeUserPublicKey: HexKey,
|
||||
chatRoomId: String,
|
||||
relayHint: String?,
|
||||
initialAddDialectUIState: AddDialectUIState = AddDialectUIState.Loading,
|
||||
nostrRepository: NostrRepository,
|
||||
chatRepository: ChatRepository,
|
||||
mantraRepository: MantraRepository
|
||||
): ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
AddDialectViewModel(
|
||||
activeUserPublicKey = activeUserPublicKey,
|
||||
chatRoomId = chatRoomId,
|
||||
relayHint = relayHint,
|
||||
initialAddDialectUIState = initialAddDialectUIState,
|
||||
nostrRepository = nostrRepository,
|
||||
chatRepository = chatRepository,
|
||||
mantraRepository = mantraRepository
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,7 @@ class ChatRoomDetailViewModel(
|
||||
ChatRoomDetailUIState.Loaded(
|
||||
localChatRoom = localChatRoom,
|
||||
artifacts = mantraRepository.getArtifacts(chatRoomId),
|
||||
dialects = mantraRepository.getDialects(chatRoomId),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package press.mantra.compose.ui.view.state
|
||||
|
||||
import press.mantra.compose.database.model.intermdiate.LocalChatRoom
|
||||
|
||||
sealed interface AddDialectUIState {
|
||||
data class Loaded(
|
||||
val localChatRoom: LocalChatRoom,
|
||||
): AddDialectUIState
|
||||
|
||||
data class Error(
|
||||
val message: String
|
||||
): AddDialectUIState
|
||||
|
||||
data object Loading: AddDialectUIState
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
package press.mantra.compose.ui.view.state
|
||||
|
||||
import press.mantra.compose.database.model.MantraArtifact
|
||||
import press.mantra.compose.database.model.MantraDialect
|
||||
import press.mantra.compose.database.model.intermdiate.LocalChatRoom
|
||||
|
||||
sealed interface ChatRoomDetailUIState {
|
||||
data class Loaded(
|
||||
val localChatRoom: LocalChatRoom,
|
||||
val artifacts: List<MantraArtifact> = emptyList(),
|
||||
val dialects: List<MantraDialect> = emptyList(),
|
||||
): ChatRoomDetailUIState
|
||||
|
||||
data class Error(
|
||||
|
||||
Reference in New Issue
Block a user