Add profile detail screen

This commit is contained in:
Kgothatso Ngako committed 2026-04-01 02:56:58 +02:00
1 parent b3b93008e5
commit 4d0e67c241
3 files changed
+273 -38

No files matched your search

@@ -3,50 +3,25 @@ package ac.aux.compose.ui.composable
import ac.aux.compose.database.model.NostrEvent import ac.aux.compose.database.model.NostrEvent
import ac.aux.compose.database.model.Profile import ac.aux.compose.database.model.Profile
import ac.aux.compose.database.model.intermdiate.LocalNostrEvent import ac.aux.compose.database.model.intermdiate.LocalNostrEvent
import ac.aux.compose.extensions.toFormattedTimeAndDateString
import ac.aux.compose.repository.NostrRepository import ac.aux.compose.repository.NostrRepository
import ac.aux.compose.ui.composable.widgets.LoadingDataIndicator import ac.aux.compose.ui.composable.widgets.LoadingDataIndicator
import ac.aux.compose.ui.composable.widgets.detail.TextNoteDetail import ac.aux.compose.ui.composable.widgets.detail.MetadataEventDetail
import ac.aux.compose.ui.composable.widgets.detail.TextNoteEventDetail
import ac.aux.compose.ui.theme.AuxTheme import ac.aux.compose.ui.theme.AuxTheme
import ac.aux.compose.ui.view.model.NostrEventDetailViewModel import ac.aux.compose.ui.view.model.NostrEventDetailViewModel
import ac.aux.compose.ui.view.state.NostrEventDetailUIState import ac.aux.compose.ui.view.state.NostrEventDetailUIState
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AddReaction
import androidx.compose.material.icons.filled.ArrowBackIosNew
import androidx.compose.material.icons.filled.ChatBubble
import androidx.compose.material.icons.filled.CurrencyBitcoin
import androidx.compose.material.icons.filled.Cyclone
import androidx.compose.material.icons.filled.Loop
import androidx.compose.material.icons.filled.MonetizationOn
import androidx.compose.material.icons.filled.Money
import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.Repeat
import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
@@ -86,18 +61,13 @@ fun NostrEventDetailScreen(
when(feedListUIState.localNostrEvent.nostrEvent.kind) { when(feedListUIState.localNostrEvent.nostrEvent.kind) {
MetadataEvent.KIND -> { MetadataEvent.KIND -> {
Column( MetadataEventDetail(
modifier = Modifier.fillMaxSize(), localNostrEvent = feedListUIState.localNostrEvent,
verticalArrangement = Arrangement.Center, onNavigateBack = onNavigateBack,
horizontalAlignment = Alignment.CenterHorizontally )
) {
Text(feedListUIState.localNostrEvent.nostrEvent.content)
Text("profile functionality coming soon.")
}
} }
TextNoteEvent.KIND -> { TextNoteEvent.KIND -> {
TextNoteDetail( TextNoteEventDetail(
feedListUIState.localNostrEvent, feedListUIState.localNostrEvent,
onNavigateBack = onNavigateBack, onNavigateBack = onNavigateBack,
onNavigateToWriteAReply = onNavigateToWriteAReply onNavigateToWriteAReply = onNavigateToWriteAReply
@@ -0,0 +1,221 @@
package ac.aux.compose.ui.composable.widgets.detail
import ac.aux.compose.database.model.NostrEvent
import ac.aux.compose.database.model.Profile
import ac.aux.compose.database.model.intermdiate.LocalNostrEvent
import ac.aux.compose.extensions.toFormattedTimeAndDateString
import ac.aux.compose.ui.theme.AuxTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AddReaction
import androidx.compose.material.icons.filled.ArrowBackIosNew
import androidx.compose.material.icons.filled.ChatBubble
import androidx.compose.material.icons.filled.CurrencyBitcoin
import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.Repeat
import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LargeTopAppBar
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.PrimaryTabRow
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Tab
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.compose.ComposeNavigator
import androidx.navigation.compose.DialogNavigator
import androidx.navigation.compose.rememberNavController
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MetadataEventDetail(
localNostrEvent: LocalNostrEvent,
onNavigateBack: () -> Unit,
) {
val profile = localNostrEvent.profile
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState())
Scaffold(
modifier = Modifier.fillMaxSize().nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
LargeTopAppBar(
navigationIcon = {
IconButton(
onClick = onNavigateBack
) {
Icon(
Icons.Default.ArrowBackIosNew,
contentDescription = "Navigate back"
)
}
},
title = {
Text(
text = profile.displayName ?: profile.userName ?: profile.publicKey,
style = MaterialTheme.typography.titleLarge
)
},
scrollBehavior = scrollBehavior
)
}
) { innerPadding ->
Column(
modifier = Modifier.padding(innerPadding).fillMaxSize()
) {
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item {
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Row(
modifier = Modifier.fillMaxWidth().padding(20.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
Icons.Default.Person,
modifier = Modifier.size(50.dp),
contentDescription = profile.displayName ?: profile.userName ?: "Profile picture"
)
Spacer(
modifier = Modifier.weight(1f)
)
Button(
onClick = {
}
) {
Text(
"Follow"
)
}
}
Text(
modifier = Modifier.fillMaxWidth().padding(
horizontal = 20.dp
),
textAlign = TextAlign.Start,
text = profile.about ?: ""
)
}
}
item {
val destinations = arrayOf("Notes", "Follows", "Following")
val navController = rememberNavController()
val startDestination = 0
val selectedDestination by rememberSaveable {
mutableIntStateOf(startDestination)
}
PrimaryTabRow(
modifier = Modifier.padding(10.dp),
selectedTabIndex = selectedDestination,
) {
destinations.forEachIndexed { index, destination ->
Tab(
selected = selectedDestination == index,
onClick = {
},
text = {
Text(
text = destination,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
)
}
}
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Spacer(
modifier = Modifier.height(30.dp)
)
Text("Profile Feed Nav Host Goes here...")
}
}
}
}
}
}
@Preview
@Composable
private fun MetadataEventEventDetailPreview() {
AuxTheme {
Surface(
modifier = Modifier.padding(20.dp)
) {
MetadataEventDetail(
localNostrEvent = LocalNostrEvent(
nostrEvent = NostrEvent(
id = "eventId",
pubKey = "publicKey",
content = """Profile""".trimIndent(),
tags = emptyArray(),
sig = "",
kind = MetadataEvent.KIND
),
profile = Profile(
publicKey = "pubKey",
displayName = "John Doe",
nip05 = "john@doe.com",
about = "I am the stone that the builder refused.",
nostrEventId = "nostrEventId"
)
),
onNavigateBack = {},
)
}
}
}
@@ -1,12 +1,17 @@
package ac.aux.compose.ui.composable.widgets.detail package ac.aux.compose.ui.composable.widgets.detail
import ac.aux.compose.database.model.NostrEvent
import ac.aux.compose.database.model.Profile
import ac.aux.compose.database.model.intermdiate.LocalNostrEvent import ac.aux.compose.database.model.intermdiate.LocalNostrEvent
import ac.aux.compose.extensions.toFormattedTimeAndDateString import ac.aux.compose.extensions.toFormattedTimeAndDateString
import ac.aux.compose.ui.theme.AuxTheme
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
@@ -26,17 +31,20 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun TextNoteDetail( fun TextNoteEventDetail(
localNostrEvent: LocalNostrEvent, localNostrEvent: LocalNostrEvent,
onNavigateBack: () -> Unit, onNavigateBack: () -> Unit,
onNavigateToWriteAReply: (String) -> Unit onNavigateToWriteAReply: (String) -> Unit
@@ -190,6 +198,7 @@ fun TextNoteDetail(
} }
) )
}, },
windowInsets = WindowInsets.navigationBars
) )
HorizontalDivider() HorizontalDivider()
@@ -201,3 +210,38 @@ fun TextNoteDetail(
} }
} }
} }
@Preview
@Composable
private fun TextNoteEventDetailPreview() {
AuxTheme {
Surface(
modifier = Modifier.padding(20.dp)
) {
TextNoteEventDetail(
localNostrEvent = LocalNostrEvent(
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"
)
),
onNavigateBack = {},
onNavigateToWriteAReply = {}
)
}
}
}