Show profile on write new note input screen.

This commit is contained in:
Kgothatso Ngako
2026-04-26 01:37:26 +02:00
parent f752b998f5
commit 8c6c734861
4 changed files with 114 additions and 48 deletions

View File

@@ -1,6 +1,11 @@
package ac.cord.auxiliary.compose.ui.composable
import ac.cord.auxiliary.compose.database.model.NostrEvent
import ac.cord.auxiliary.compose.database.model.Profile
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalProfileWithFollowing
import ac.cord.auxiliary.compose.repository.NostrRepository
import ac.cord.auxiliary.compose.ui.composable.widgets.LoadingDataIndicator
import ac.cord.auxiliary.compose.ui.composable.widgets.profile.ProfileAvatar
import ac.cord.auxiliary.compose.ui.theme.AuxTheme
import ac.cord.auxiliary.compose.ui.view.model.WriteNewNoteViewModel
import ac.cord.auxiliary.compose.ui.view.state.WriteNewNoteUIState
@@ -24,6 +29,7 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.key
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.KeyboardType
@@ -31,11 +37,12 @@ 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.nip10Notes.TextNoteEvent
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun WriteNewNoteScreen(
initialWriteNewNoteUIState: WriteNewNoteUIState = WriteNewNoteUIState.InputPrompt,
initialWriteNewNoteUIState: WriteNewNoteUIState = WriteNewNoteUIState.Loading,
onNostrEventPublished: () -> Unit,
nostrRepository: NostrRepository
) {
@@ -58,7 +65,10 @@ fun WriteNewNoteScreen(
verticalArrangement = Arrangement.spacedBy(20.dp)
) {
when (val writeNewNoteUIState = writeNewNoteViewModel.writeNewNoteUIState.value) {
when (val writeNewNoteUIState = writeNewNoteViewModel.writeNewNoteUIState) {
is WriteNewNoteUIState.Loading -> {
LoadingDataIndicator()
}
is WriteNewNoteUIState.InputPrompt -> {
Text(
"Write new note",
@@ -98,24 +108,18 @@ fun WriteNewNoteScreen(
)
},
leadingIcon = {
Icon(
Icons.Default.Create,
contentDescription = "Write note"
ProfileAvatar(
profile = writeNewNoteUIState.localProfile.profile,
size = 35.dp
)
}
)
Button(
onClick = {
writeNewNoteViewModel.validateInput().let { isInputValid ->
if (isInputValid) {
writeNewNoteViewModel.writeNewNoteUIState.value =
WriteNewNoteUIState.ConfirmNote(
text = writeNewNoteViewModel.writeNewNoteFormState.textField.text.value,
)
}
}
writeNewNoteViewModel.confirmNote(
localProfile = writeNewNoteUIState.localProfile
)
},
) {
Text(
@@ -190,6 +194,10 @@ fun WriteNewNoteScreen(
}
}
}
key(true) {
writeNewNoteViewModel.initiate()
}
}
@Preview
@@ -201,33 +209,28 @@ private fun WriteNewNoteScreenPreview() {
) {
WriteNewNoteScreen(
initialWriteNewNoteUIState =
WriteNewNoteUIState.InputPrompt,
// CreateProfileUIState.Error,
// CreateProfileUIState.ConfirmInput(
// name = "Alan Turing",
// bio = "Polyglot: Math... is my middle name, computer scientist. cryptographer, and gold hider."
// ),
// CreateProfileUIState.UnsignedProfile(
// unsignedNostrEvent = UnsignedNostrEvent(
// kind = 0,
// content = "Something here",
// tags = emptyArray(),
// ),
// name = "Alan Turing",
// bio = "Polyglot: Math... is my middle name, computer scientist. cryptographer, and gold hider."
// ),
// CreateProfileUIState.UnbroadcastedProfile(
// nostrEvent = NostrEvent(
// id = "",
// pubKey = "",
// kind = 0,
// content = "Something here",
// tags = emptyArray(),
// sig = ""
// ),
// name = "Alan Turing",
// bio = "Polyglot: Math... is my middle name, computer scientist. cryptographer, and gold hider."
// ),
WriteNewNoteUIState.InputPrompt(
localProfile = LocalProfileWithFollowing(
nostrEvent = NostrEvent(
id = "eventId",
pubKey = "publicKey",
content = """Lorem Ipsum is simply dummy text of the printing and typesetting industry.
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.""".trimIndent(),
tags = emptyArray(),
sig = "",
kind = TextNoteEvent.KIND
),
profile = Profile(
publicKey = "pubKey",
displayName = "John Doe",
nostrEventId = "nostrEventId"
),
following = emptyList()
)
),
onNostrEventPublished = {},
nostrRepository = NostrRepository.NO_OP_NOSTR_REPOSITORY)
}

View File

@@ -26,6 +26,20 @@ import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
import kotlin.math.abs
@Composable
fun ProfileAvatar(
size: Dp = 55.dp,
shape: Shape = CircleShape,
profile: Profile
) {
ProfileAvatar(
size = size,
shape = shape,
profile = profile,
publicKey = profile.publicKey
)
}
@Composable
fun ProfileAvatar(
size: Dp = 55.dp,

View File

@@ -1,7 +1,10 @@
package ac.cord.auxiliary.compose.ui.view.model
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalProfile
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalProfileWithFollowing
import ac.cord.auxiliary.compose.managers.SeedManager
import ac.cord.auxiliary.compose.repository.NostrRepository
import ac.cord.auxiliary.compose.ui.view.state.HomeScreenUIState
import ac.cord.auxiliary.compose.ui.view.state.WriteNewNoteUIState
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
@@ -10,6 +13,8 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import ac.cord.auxiliary.compose.ui.view.state.form.WriteNewNoteFormState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.lifecycle.viewModelScope
import co.touchlab.kermit.Logger
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
@@ -42,9 +47,47 @@ class WriteNewNoteViewModel(
val isActionPending: MutableState<Boolean> = mutableStateOf(false)
var writeNewNoteUIState: MutableState<WriteNewNoteUIState> = mutableStateOf(
initialWriteNewNoteUIState
)
var writeNewNoteUIState: WriteNewNoteUIState by mutableStateOf(initialWriteNewNoteUIState)
private set
fun initiate() {
observeActiveUserProfileWithFollowing()
}
fun observeActiveUserProfileWithFollowing() {
logger.d("observeActiveUserProfileWithFollowing")
viewModelScope.launch(Dispatchers.IO) {
val activePublicKey = SeedManager.activePublicKey().toHexKey()
// TODO: Get note being replied too...
// TODO: Get note being quoted...
// TODO: Get users being mentioned...
nostrRepository.observeProfileWithFollowing(
activePublicKey
).collect { profileWithFollowing ->
writeNewNoteUIState = if (profileWithFollowing != null) {
WriteNewNoteUIState.InputPrompt(
localProfile = profileWithFollowing
)
} else {
WriteNewNoteUIState.Error
}
}
}
}
fun confirmNote(localProfile: LocalProfileWithFollowing) {
validateInput().let { isInputValid ->
if (isInputValid) {
writeNewNoteUIState =
WriteNewNoteUIState.ConfirmNote(
localProfile = localProfile,
text = writeNewNoteFormState.textField.text.value,
)
}
}
}
fun validateInput(): Boolean {
if (writeNewNoteFormState.textField.text.value.isBlank()) {
@@ -63,14 +106,12 @@ class WriteNewNoteViewModel(
isActionPending.value = true
viewModelScope.launch(Dispatchers.IO) {
nostrRepository.createNewTextNote(
publicKey = SeedManager.activePublicKey().toHexKey(),
text = writeNewNoteFormState.textField.text.value,
onSuccess = onNostrEventPublished,
onError = {
writeNewNoteUIState.value = WriteNewNoteUIState.Error
writeNewNoteUIState = WriteNewNoteUIState.Error
}
)
}

View File

@@ -1,11 +1,19 @@
package ac.cord.auxiliary.compose.ui.view.state
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalProfile
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalProfileWithFollowing
abstract class WriteNewNoteUIState {
data object Loading: WriteNewNoteUIState()
data object Error: WriteNewNoteUIState()
data object InputPrompt: WriteNewNoteUIState()
data class InputPrompt(
val localProfile: LocalProfileWithFollowing
): WriteNewNoteUIState()
data class ConfirmNote(
val localProfile: LocalProfileWithFollowing,
val text: String,
) : WriteNewNoteUIState()