diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/composable/NostrEventDetailScreen.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/composable/NostrEventDetailScreen.kt index 706a6312..630d27e8 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/composable/NostrEventDetailScreen.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/composable/NostrEventDetailScreen.kt @@ -3,50 +3,25 @@ package ac.aux.compose.ui.composable 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.repository.NostrRepository 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.view.model.NostrEventDetailViewModel import ac.aux.compose.ui.view.state.NostrEventDetailUIState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row 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.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.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.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 @@ -86,18 +61,13 @@ fun NostrEventDetailScreen( when(feedListUIState.localNostrEvent.nostrEvent.kind) { MetadataEvent.KIND -> { - Column( - modifier = Modifier.fillMaxSize(), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text(feedListUIState.localNostrEvent.nostrEvent.content) - - Text("profile functionality coming soon.") - } + MetadataEventDetail( + localNostrEvent = feedListUIState.localNostrEvent, + onNavigateBack = onNavigateBack, + ) } TextNoteEvent.KIND -> { - TextNoteDetail( + TextNoteEventDetail( feedListUIState.localNostrEvent, onNavigateBack = onNavigateBack, onNavigateToWriteAReply = onNavigateToWriteAReply diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/composable/widgets/detail/MetadataEventDetail.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/composable/widgets/detail/MetadataEventDetail.kt new file mode 100644 index 00000000..684e22b8 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/composable/widgets/detail/MetadataEventDetail.kt @@ -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 = {}, + ) + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/composable/widgets/detail/TextNoteDetail.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/composable/widgets/detail/TextNoteEventDetail.kt similarity index 79% rename from composeApp/src/commonMain/kotlin/ac/aux/compose/ui/composable/widgets/detail/TextNoteDetail.kt rename to composeApp/src/commonMain/kotlin/ac/aux/compose/ui/composable/widgets/detail/TextNoteEventDetail.kt index 41512d8b..d1cb752d 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/composable/widgets/detail/TextNoteDetail.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/composable/widgets/detail/TextNoteEventDetail.kt @@ -1,12 +1,17 @@ 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.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn @@ -26,17 +31,20 @@ import androidx.compose.material3.Icon import androidx.compose.material3.IconButton 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.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 com.vitorpamplona.quartz.nip10Notes.TextNoteEvent @OptIn(ExperimentalMaterial3Api::class) @Composable -fun TextNoteDetail( +fun TextNoteEventDetail( localNostrEvent: LocalNostrEvent, onNavigateBack: () -> Unit, onNavigateToWriteAReply: (String) -> Unit @@ -190,6 +198,7 @@ fun TextNoteDetail( } ) }, + windowInsets = WindowInsets.navigationBars ) HorizontalDivider() @@ -200,4 +209,39 @@ 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 = {} + ) + } + } } \ No newline at end of file