From aaf6bbad83ddae94fa9b69385f6f626b270314ae Mon Sep 17 00:00:00 2001 From: Kgothatso Ngako Date: Mon, 6 Jul 2026 13:13:37 +0200 Subject: [PATCH] Clean up code for some of the imports --- .../database/converters/TorchConverters.kt | 13 +- .../dao/NegentropySynchronizeRequestDao.kt | 7 +- .../compose/database/model/GiftWrapPayload.kt | 9 +- .../database/model/MarmotInnerEvent.kt | 5 +- .../model/intermdiate/LocalChatRoom.kt | 11 +- .../model/intermdiate/LocalProfile.kt | 6 +- .../repository/DatabaseChatRepository.kt | 22 +- .../compose/repository/ChatRepository.kt | 14 +- .../ui/composable/ChatRoomDetailScreen.kt | 9 +- .../torch/compose/ui/composable/HomeScreen.kt | 46 ++-- .../ui/composable/NostrEventDetailScreen.kt | 41 ++-- .../ui/composable/navigation/TorchNavHost.kt | 200 ++++++++++-------- .../widgets/detail/MetadataEventDetail.kt | 42 ++-- .../ChatRoomDetailMessageListViewModel.kt | 18 +- .../ui/view/model/ChatRoomDetailViewModel.kt | 5 +- .../ui/view/state/ChatRoomDetailUIState.kt | 4 +- 16 files changed, 268 insertions(+), 184 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/converters/TorchConverters.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/converters/TorchConverters.kt index bbc802d2..0aab99ce 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/database/converters/TorchConverters.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/converters/TorchConverters.kt @@ -1,6 +1,7 @@ package at.torch.compose.database.converters import androidx.room3.TypeConverter +import at.torch.compose.database.model.types.SynchronizationFilter import co.touchlab.kermit.Logger import kotlinx.serialization.json.Json import kotlin.time.Instant @@ -72,7 +73,7 @@ class TorchConverters { } @TypeConverter - fun fromFilterArray(value: Array?): String? = try { + fun fromFilterArray(value: Array?): String? = try { return value?.let { Json.encodeToString(value) } @@ -82,9 +83,9 @@ class TorchConverters { } @TypeConverter - fun toFilterArray(value: String?): Array? = try { + fun toFilterArray(value: String?): Array? = try { return value?.let { - Json.decodeFromString>(it) + Json.decodeFromString>(it) } } catch (e: Throwable) { logger.e("Failed to convert to FilterArray $value", e) @@ -92,7 +93,7 @@ class TorchConverters { } @TypeConverter - fun fromSynchronizationFilter(value: at.torch.compose.database.model.types.SynchronizationFilter?): String? = try { + fun fromSynchronizationFilter(value: SynchronizationFilter?): String? = try { return value?.let { Json.encodeToString(value) } @@ -102,9 +103,9 @@ class TorchConverters { } @TypeConverter - fun toSynchronizationFilter(value: String?): at.torch.compose.database.model.types.SynchronizationFilter? = try { + fun toSynchronizationFilter(value: String?): SynchronizationFilter? = try { return value?.let { - Json.decodeFromString(it) + Json.decodeFromString(it) } } catch (e: Throwable) { logger.e("Failed to convert to SynchronizationFilter $value", e) diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/NegentropySynchronizeRequestDao.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/NegentropySynchronizeRequestDao.kt index 4c139cca..9be52792 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/NegentropySynchronizeRequestDao.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/NegentropySynchronizeRequestDao.kt @@ -5,6 +5,7 @@ import androidx.room3.Insert import androidx.room3.OnConflictStrategy.Companion.IGNORE import androidx.room3.Query import androidx.room3.Upsert +import at.torch.compose.database.model.NegentropySynchronizeRequest import kotlinx.coroutines.flow.Flow import kotlin.time.Clock import kotlin.time.Instant @@ -12,16 +13,16 @@ import kotlin.time.Instant @Dao interface NegentropySynchronizeRequestDao { @Query("SELECT * FROM NegentropySynchronizeRequest WHERE status = :status AND createdAt > :createdAt") - fun observeNegentropySynchronizeRequestsByStatus(status: String, createdAt: Instant = Clock.System.now()): Flow + fun observeNegentropySynchronizeRequestsByStatus(status: String, createdAt: Instant = Clock.System.now()): Flow @Query("SELECT COUNT(*) FROM NegentropySynchronizeRequest WHERE purpose = :purpose AND status IN (:status) AND createdAt > :createdAt") fun observeNegentropySynchronizeRequestByPurposeAndStatusCount(purpose: String, status: List, createdAt: Instant = Clock.System.now()): Flow @Upsert - fun upsert(negentropySynchronizeRequest: at.torch.compose.database.model.NegentropySynchronizeRequest) + fun upsert(negentropySynchronizeRequest: NegentropySynchronizeRequest) @Insert( onConflict = IGNORE ) - fun insert(negentropySynchronizeRequests: List) + fun insert(negentropySynchronizeRequests: List) } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/GiftWrapPayload.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/GiftWrapPayload.kt index 2c78c2c5..446a06a7 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/GiftWrapPayload.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/GiftWrapPayload.kt @@ -4,6 +4,10 @@ import androidx.room3.Entity import androidx.room3.ForeignKey import androidx.room3.Ignore import androidx.room3.PrimaryKey +import at.torch.compose.database.model.traits.LocalStoreEntity +import at.torch.compose.database.model.traits.SoftDeletableEntity +import at.torch.compose.database.model.traits.TimestampedEntity +import at.torch.compose.database.model.traits.UserViewableEntity import co.touchlab.kermit.Logger import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.Kind @@ -74,10 +78,7 @@ data class GiftWrapPayload( override val savedAt: Instant = Clock.System.now(), override val viewedAt: Instant? = null, override val deletedAt: Instant? = null, // Who this message should be seen by (used to derive conversationId) -): at.torch.compose.database.model.traits.TimestampedEntity, - at.torch.compose.database.model.traits.LocalStoreEntity, - at.torch.compose.database.model.traits.UserViewableEntity, - at.torch.compose.database.model.traits.SoftDeletableEntity { +): TimestampedEntity, LocalStoreEntity, UserViewableEntity, SoftDeletableEntity { @Ignore private val logger = Logger.withTag(TAG) diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/MarmotInnerEvent.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/MarmotInnerEvent.kt index 9b193aea..6f461716 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/MarmotInnerEvent.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/MarmotInnerEvent.kt @@ -90,10 +90,7 @@ data class MarmotInnerEvent( // TODO: Rename this to GiftWrapPayload... override val savedAt: Instant = Clock.System.now(), override val viewedAt: Instant? = null, override val deletedAt: Instant? = null, // Who this message should be seen by (used to derive conversationId) -): TimestampedEntity, - LocalStoreEntity, - UserViewableEntity, - SoftDeletableEntity { +): TimestampedEntity, LocalStoreEntity, UserViewableEntity, SoftDeletableEntity { @Ignore private val logger = Logger.withTag(TAG) diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/intermdiate/LocalChatRoom.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/intermdiate/LocalChatRoom.kt index 2ed4caab..95c32576 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/intermdiate/LocalChatRoom.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/intermdiate/LocalChatRoom.kt @@ -7,12 +7,15 @@ import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.withStyle import androidx.room3.Embedded import androidx.room3.Relation +import at.torch.compose.database.model.ChatRoom +import at.torch.compose.database.model.Participant +import at.torch.compose.ui.composable.widgets.profile.ProfileColor data class LocalChatRoom( - @Embedded val chatRoom: at.torch.compose.database.model.ChatRoom, + @Embedded val chatRoom: ChatRoom, @Relation( - entity = at.torch.compose.database.model.Participant::class, + entity = Participant::class, parentColumns = ["id"], entityColumns = ["chatRoomId"], ) @@ -23,7 +26,7 @@ data class LocalChatRoom( if (chatRoom.subject != null) { Text( text = chatRoom.subject, - color = at.torch.compose.ui.composable.widgets.profile.ProfileColor.fromPublicKey(chatRoom.id) + color = ProfileColor.fromPublicKey(chatRoom.id) ) } else { if (localParticipants.size == 1) { @@ -33,7 +36,7 @@ data class LocalChatRoom( } else { // Remove the active user publicKey from participants... val participantNames = localParticipants.filter { it.participant.participantPublicKey != chatRoom.userPublicKey }.map { buildAnnotatedString { - withStyle(style = SpanStyle(color = at.torch.compose.ui.composable.widgets.profile.ProfileColor.fromPublicKey(it.participant.participantPublicKey))) { + withStyle(style = SpanStyle(color = ProfileColor.fromPublicKey(it.participant.participantPublicKey))) { append(it.profile?.humanReadableNameOrPubkey() ?: "unknown participant") } } } diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/intermdiate/LocalProfile.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/intermdiate/LocalProfile.kt index f7a2e157..b1a6599c 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/intermdiate/LocalProfile.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/intermdiate/LocalProfile.kt @@ -2,13 +2,15 @@ package at.torch.compose.database.model.intermdiate import androidx.room3.Embedded import androidx.room3.Relation +import at.torch.compose.database.model.NostrEvent +import at.torch.compose.database.model.Profile data class LocalProfile( - @Embedded val nostrEvent: at.torch.compose.database.model.NostrEvent, + @Embedded val nostrEvent: NostrEvent, @Relation( parentColumns = ["pubKey"], entityColumns = ["publicKey"] ) - val profile: at.torch.compose.database.model.Profile, + val profile: Profile, ) diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/repository/DatabaseChatRepository.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/repository/DatabaseChatRepository.kt index c18a333d..16b95f68 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/database/repository/DatabaseChatRepository.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/repository/DatabaseChatRepository.kt @@ -1,5 +1,7 @@ package at.torch.compose.database.repository +import at.torch.compose.database.GENESIS_AT +import at.torch.compose.database.TorchDatabase import at.torch.compose.database.model.ChatMessage import at.torch.compose.database.model.ChatRoom import at.torch.compose.database.model.GiftWrapPayload @@ -7,6 +9,8 @@ import at.torch.compose.database.model.MarmotInnerEvent import at.torch.compose.database.model.MarmotKeyPackage import at.torch.compose.database.model.Participant import at.torch.compose.database.model.Profile +import at.torch.compose.database.model.intermdiate.LocalChatMessage +import at.torch.compose.database.model.intermdiate.LocalChatRoom import at.torch.compose.database.model.intermdiate.LocalProfile import at.torch.compose.extensions.toHex import at.torch.compose.nostr.Relays @@ -39,30 +43,30 @@ import kotlin.time.Clock import kotlin.time.Instant class DatabaseChatRepository( - private val database: at.torch.compose.database.TorchDatabase, + private val database: TorchDatabase, private val scope: CoroutineScope ): at.torch.compose.repository.ChatRepository { val logger = Logger.withTag(TAG) - override suspend fun observeChatRoomListByPublicKey(publicKey: String): Flow> { + override suspend fun observeChatRoomListByPublicKey(publicKey: String): Flow> { return database.chatRoomDao().observeChatRoomListByUserPublicKey(publicKey) } - override suspend fun getChatRoomListByPublicKey(publicKey: String): List { + override suspend fun getChatRoomListByPublicKey(publicKey: String): List { return database.chatRoomDao().getChatRoomListByUserPublicKey(publicKey) } - override suspend fun getChatRoomByIdentifier(id: HexKey): at.torch.compose.database.model.intermdiate.LocalChatRoom? { + override suspend fun getChatRoomByIdentifier(id: HexKey): LocalChatRoom? { return database.chatRoomDao().findChatRoomById(id) } override suspend fun getAllParticipantsWithPubKey(publicKey: HexKey): List { return database.participantDao().findParticipantByPublicKey(publicKey) } - override suspend fun getChatMessageListByChatRoomId(chatRoomId: String): List { + override suspend fun getChatMessageListByChatRoomId(chatRoomId: String): List { return database.chatMessageDao().getChatMessagesByChatRoomId(chatRoomId) } - override suspend fun observeChatMessageListByChatRoomId(chatRoomId: String): Flow> { + override suspend fun observeChatMessageListByChatRoomId(chatRoomId: String): Flow> { return database.chatMessageDao().observeChatMessagesByChatRoomId(chatRoomId) } @@ -73,7 +77,7 @@ class DatabaseChatRepository( relayHint: String?, defaultSubject: String?, mlsGroupState: String? - ): at.torch.compose.database.model.intermdiate.LocalChatRoom? = try { + ): LocalChatRoom? = try { return database.nostrNip17Dao().getOrCreateChatRoom( chatRoomId = chatRoomId, activeUserPublicKey = activeUserPublicKey, @@ -95,7 +99,7 @@ class DatabaseChatRepository( authors = arrayOf( publicKey ), - since = _root_ide_package_.at.torch.compose.database.GENESIS_AT, + since = GENESIS_AT, limit = 5 ).firstOrNull()?.let { nostrEvent -> if (nostrEvent.kind != ChatMessageRelayListEvent.KIND) { @@ -136,7 +140,7 @@ class DatabaseChatRepository( override suspend fun sendChatMessage( text: String, - localChatRoom: at.torch.compose.database.model.intermdiate.LocalChatRoom, + localChatRoom: LocalChatRoom, messageType: Kind ) { logger.i("sendChatMessage($text): $localChatRoom") diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/repository/ChatRepository.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/repository/ChatRepository.kt index 443908c8..39f55a57 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/repository/ChatRepository.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/repository/ChatRepository.kt @@ -1,5 +1,7 @@ package at.torch.compose.repository +import at.torch.compose.database.model.ChatRoom +import at.torch.compose.database.model.GiftWrapPayload import at.torch.compose.database.model.MarmotKeyPackage import at.torch.compose.database.model.Participant import at.torch.compose.database.model.Profile @@ -54,11 +56,11 @@ interface ChatRepository { messageType: Kind = ChatMessageEvent.KIND ) - fun updateChatRoomSubject(publicKey: String, subject: String): at.torch.compose.database.model.ChatRoom? + fun updateChatRoomSubject(publicKey: String, subject: String): ChatRoom? - suspend fun observeUnsealedGiftWrapPayloads(publicKey: HexKey): Flow + suspend fun observeUnsealedGiftWrapPayloads(publicKey: HexKey): Flow - suspend fun sealGiftWrapPayload(giftWrapPayload: at.torch.compose.database.model.GiftWrapPayload, nostrSignerSync: NostrSignerSync) + suspend fun sealGiftWrapPayload(giftWrapPayload: GiftWrapPayload, nostrSignerSync: NostrSignerSync) companion object { val NO_OP_CHAT_REPOSITORY = object: ChatRepository { @@ -125,16 +127,16 @@ interface ChatRepository { // TODO("Not yet implemented") } - override fun updateChatRoomSubject(publicKey: String, subject: String): at.torch.compose.database.model.ChatRoom? { + override fun updateChatRoomSubject(publicKey: String, subject: String): ChatRoom? { return null } - override suspend fun observeUnsealedGiftWrapPayloads(publicKey: HexKey): Flow { + override suspend fun observeUnsealedGiftWrapPayloads(publicKey: HexKey): Flow { TODO("Not yet implemented") } override suspend fun sealGiftWrapPayload( - giftWrapPayload: at.torch.compose.database.model.GiftWrapPayload, + giftWrapPayload: GiftWrapPayload, nostrSignerSync: NostrSignerSync ) { TODO("Not yet implemented") diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/ChatRoomDetailScreen.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/ChatRoomDetailScreen.kt index 546a3776..895621f8 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/ChatRoomDetailScreen.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/ChatRoomDetailScreen.kt @@ -37,10 +37,13 @@ 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 at.torch.compose.database.model.ChatRoom +import at.torch.compose.database.model.intermdiate.LocalChatRoom import at.torch.compose.repository.ChatRepository import at.torch.compose.repository.NostrRepository import at.torch.compose.ui.composable.navigation.routes.Route import at.torch.compose.ui.composable.widgets.LoadingDataIndicator +import at.torch.compose.ui.theme.TorchTheme import at.torch.compose.ui.view.model.ChatRoomDetailViewModel import at.torch.compose.ui.view.state.ChatRoomDetailUIState import com.vitorpamplona.quartz.nip01Core.core.HexKey @@ -312,7 +315,7 @@ fun ChatRoomDetailScreen( @Preview @Composable private fun ChatRoomDetailScreenPreview() { - _root_ide_package_.at.torch.compose.ui.theme.TorchTheme { + TorchTheme { Surface( modifier = Modifier.fillMaxSize() ) { @@ -321,8 +324,8 @@ private fun ChatRoomDetailScreenPreview() { chatRoomId = "publicKey", relayHint = null, initialChatRoomDetailUIState = ChatRoomDetailUIState.Loaded( - localChatRoom = _root_ide_package_.at.torch.compose.database.model.intermdiate.LocalChatRoom( - chatRoom = _root_ide_package_.at.torch.compose.database.model.ChatRoom( + localChatRoom = LocalChatRoom( + chatRoom = ChatRoom( id = "", userPublicKey = "", subject = "Message title", diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/HomeScreen.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/HomeScreen.kt index 7ef49b85..5cdbc232 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/HomeScreen.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/HomeScreen.kt @@ -32,9 +32,19 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel +import at.torch.compose.database.model.NostrEvent +import at.torch.compose.database.model.Profile +import at.torch.compose.database.model.intermdiate.LocalProfileWithFollowing +import at.torch.compose.repository.ChatRepository +import at.torch.compose.repository.NostrRepository import at.torch.compose.ui.composable.navigation.routes.ActiveProfileRoute import at.torch.compose.ui.composable.navigation.routes.NostrEventDetailRoute +import at.torch.compose.ui.composable.navigation.routes.Route +import at.torch.compose.ui.composable.widgets.LoadingDataIndicator +import at.torch.compose.ui.theme.TorchTheme import at.torch.compose.ui.view.model.HomeScreenType +import at.torch.compose.ui.view.model.HomeViewModel +import at.torch.compose.ui.view.state.HomeScreenUIState import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import kotlinx.coroutines.launch @@ -43,18 +53,18 @@ import kotlinx.coroutines.launch @Composable fun HomeScreen( activeUserPublicKey: HexKey, - initialHomeScreenUIState: at.torch.compose.ui.view.state.HomeScreenUIState = at.torch.compose.ui.view.state.HomeScreenUIState.Loading, - onNavigateToEvent: (at.torch.compose.ui.composable.navigation.routes.Route) -> Unit, - onNavigateToDirectMessageDetail: (at.torch.compose.ui.composable.navigation.routes.Route) -> Unit, + initialHomeScreenUIState: HomeScreenUIState = HomeScreenUIState.Loading, + onNavigateToEvent: (Route) -> Unit, + onNavigateToDirectMessageDetail: (Route) -> Unit, onNavigateToChatRoomCreation: () -> Unit, onNavigateToSearch: () -> Unit, - nostrRepository: at.torch.compose.repository.NostrRepository, - chatRepository: at.torch.compose.repository.ChatRepository + nostrRepository: NostrRepository, + chatRepository: ChatRepository ) { val scope = rememberCoroutineScope() - val homeScreenViewModel: at.torch.compose.ui.view.model.HomeViewModel = viewModel( - factory = at.torch.compose.ui.view.model.HomeViewModel.factory( + val homeScreenViewModel: HomeViewModel = viewModel( + factory = HomeViewModel.factory( activeUserPublicKey = activeUserPublicKey, initialHomeScreenUIState = initialHomeScreenUIState, nostrRepository = nostrRepository, @@ -63,7 +73,7 @@ fun HomeScreen( ) when(val homeScreenUIState = homeScreenViewModel.homeScreenUIState) { - at.torch.compose.ui.view.state.HomeScreenUIState.Error -> { + HomeScreenUIState.Error -> { Scaffold { innerPadding -> Column( modifier = Modifier.padding(innerPadding).fillMaxSize(), @@ -84,7 +94,7 @@ fun HomeScreen( } } - is at.torch.compose.ui.view.state.HomeScreenUIState.Loaded -> { + is HomeScreenUIState.Loaded -> { Scaffold( modifier = Modifier, topBar = { @@ -206,8 +216,8 @@ fun HomeScreen( } } } - at.torch.compose.ui.view.state.HomeScreenUIState.Loading -> { - _root_ide_package_.at.torch.compose.ui.composable.widgets.LoadingDataIndicator() + HomeScreenUIState.Loading -> { + LoadingDataIndicator() } } @@ -219,15 +229,15 @@ fun HomeScreen( @Preview @Composable private fun HomeScreenPreview() { - _root_ide_package_.at.torch.compose.ui.theme.TorchTheme { + TorchTheme { Surface( modifier = Modifier.padding(20.dp) ) { HomeScreen( activeUserPublicKey = "", - initialHomeScreenUIState = at.torch.compose.ui.view.state.HomeScreenUIState.Loaded( - profileWithFollowing = _root_ide_package_.at.torch.compose.database.model.intermdiate.LocalProfileWithFollowing( - nostrEvent = _root_ide_package_.at.torch.compose.database.model.NostrEvent( + initialHomeScreenUIState = HomeScreenUIState.Loaded( + profileWithFollowing = LocalProfileWithFollowing( + nostrEvent = NostrEvent( id = "eventId", pubKey = "publicKey", content = """Lorem Ipsum is simply dummy text of the printing and typesetting industry. @@ -239,7 +249,7 @@ It has survived not only five centuries, but also the leap into electronic types sig = "", kind = TextNoteEvent.KIND ), - profile = _root_ide_package_.at.torch.compose.database.model.Profile( + profile = Profile( publicKey = "pubKey", displayName = "John Doe", nostrEventId = "nostrEventId" @@ -251,8 +261,8 @@ It has survived not only five centuries, but also the leap into electronic types onNavigateToChatRoomCreation = {}, onNavigateToSearch = {}, onNavigateToDirectMessageDetail = {}, - nostrRepository = at.torch.compose.repository.NostrRepository.NO_OP_NOSTR_REPOSITORY, - chatRepository = at.torch.compose.repository.ChatRepository.NO_OP_CHAT_REPOSITORY + nostrRepository = NostrRepository.NO_OP_NOSTR_REPOSITORY, + chatRepository = ChatRepository.NO_OP_CHAT_REPOSITORY ) } } diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/NostrEventDetailScreen.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/NostrEventDetailScreen.kt index add61a59..d92c3ec9 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/NostrEventDetailScreen.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/NostrEventDetailScreen.kt @@ -15,8 +15,17 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel +import at.torch.compose.database.model.NostrEvent +import at.torch.compose.database.model.Profile +import at.torch.compose.database.model.intermdiate.LocalNostrEvent +import at.torch.compose.repository.NostrRepository import at.torch.compose.ui.composable.navigation.routes.Route +import at.torch.compose.ui.composable.widgets.LoadingDataIndicator import at.torch.compose.ui.composable.widgets.detail.MetadataEventDetail +import at.torch.compose.ui.composable.widgets.detail.TextNoteEventDetail +import at.torch.compose.ui.theme.TorchTheme +import at.torch.compose.ui.view.model.NostrEventDetailViewModel +import at.torch.compose.ui.view.state.NostrEventDetailUIState import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent @@ -25,10 +34,10 @@ import com.vitorpamplona.quartz.nip18Reposts.RepostEvent @OptIn(ExperimentalMaterial3Api::class) @Composable fun NostrEventDetailScreen( - initialNostrEventDetailUIState: at.torch.compose.ui.view.state.NostrEventDetailUIState, + initialNostrEventDetailUIState: NostrEventDetailUIState, activeUserPublicKey: HexKey, nostrEventId: HexKey, - nostrRepository: at.torch.compose.repository.NostrRepository, + nostrRepository: NostrRepository, onNavigateBack: () -> Unit, onNavigateToEvent: (Route) -> Unit, onNavigateToDirectMessage: (Route) -> Unit, @@ -36,8 +45,8 @@ fun NostrEventDetailScreen( onNavigateToWriteAReply: (String) -> Unit, onNavigateToQuoteNostrEvent: (String) -> Unit, ) { - val nostrEventDetailViewModel: at.torch.compose.ui.view.model.NostrEventDetailViewModel = viewModel( - factory = at.torch.compose.ui.view.model.NostrEventDetailViewModel.factory( + val nostrEventDetailViewModel: NostrEventDetailViewModel = viewModel( + factory = NostrEventDetailViewModel.factory( nostrEventId = nostrEventId, initialNostrEventDetailUIState = initialNostrEventDetailUIState, nostrRepository = nostrRepository, @@ -46,7 +55,7 @@ fun NostrEventDetailScreen( ) when(val feedListUIState = nostrEventDetailViewModel.nostrEventDetailUIState) { - at.torch.compose.ui.view.state.NostrEventDetailUIState.Error -> { + NostrEventDetailUIState.Error -> { Column( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, @@ -55,7 +64,7 @@ fun NostrEventDetailScreen( Text("Something went wrong") } } - is at.torch.compose.ui.view.state.NostrEventDetailUIState.Loaded -> { + is NostrEventDetailUIState.Loaded -> { when(feedListUIState.localNostrEvent.nostrEvent.kind) { MetadataEvent.KIND -> { @@ -70,7 +79,7 @@ fun NostrEventDetailScreen( ) } TextNoteEvent.KIND -> { - at.torch.compose.ui.composable.widgets.detail.TextNoteEventDetail( + TextNoteEventDetail( feedListUIState.localNostrEvent, onNavigateBack = onNavigateBack, onNavigateToWriteAReply = onNavigateToWriteAReply, @@ -109,14 +118,14 @@ fun NostrEventDetailScreen( } } } - at.torch.compose.ui.view.state.NostrEventDetailUIState.Loading -> { - at.torch.compose.ui.composable.widgets.LoadingDataIndicator() + NostrEventDetailUIState.Loading -> { + LoadingDataIndicator() LaunchedEffect(true) { nostrEventDetailViewModel.loadNostrFeed() } } - at.torch.compose.ui.view.state.NostrEventDetailUIState.NotFound -> { + NostrEventDetailUIState.NotFound -> { Column( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, @@ -131,14 +140,14 @@ fun NostrEventDetailScreen( @Preview @Composable private fun NostrEventDetailScreenPreview() { - at.torch.compose.ui.theme.TorchTheme { + TorchTheme { Surface( modifier = Modifier.padding(20.dp) ) { NostrEventDetailScreen( - initialNostrEventDetailUIState = at.torch.compose.ui.view.state.NostrEventDetailUIState.Loaded( - localNostrEvent = at.torch.compose.database.model.intermdiate.LocalNostrEvent( - nostrEvent = at.torch.compose.database.model.NostrEvent( + initialNostrEventDetailUIState = NostrEventDetailUIState.Loaded( + localNostrEvent = LocalNostrEvent( + nostrEvent = NostrEvent( id = "eventId", pubKey = "publicKey", content = """Lorem Ipsum is simply dummy text of the printing and typesetting industry. @@ -150,7 +159,7 @@ It has survived not only five centuries, but also the leap into electronic types sig = "", kind = TextNoteEvent.KIND ), - profile = at.torch.compose.database.model.Profile( + profile = Profile( publicKey = "pubKey", displayName = "John Doe", nostrEventId = "nostrEventId" @@ -159,7 +168,7 @@ It has survived not only five centuries, but also the leap into electronic types ), nostrEventId = "", activeUserPublicKey = "", - nostrRepository = at.torch.compose.repository.NostrRepository.NO_OP_NOSTR_REPOSITORY, + nostrRepository = NostrRepository.NO_OP_NOSTR_REPOSITORY, onNavigateBack = {}, onNavigateToEvent = {}, onNavigateToWriteAReply = {}, diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/navigation/TorchNavHost.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/navigation/TorchNavHost.kt index cefb9f2b..b57d6476 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/navigation/TorchNavHost.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/navigation/TorchNavHost.kt @@ -12,26 +12,61 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.toRoute +import at.torch.compose.TorchGlobal +import at.torch.compose.database.repository.DatabaseChatRepository import at.torch.compose.database.repository.DatabaseMarmotRepository +import at.torch.compose.database.repository.DatabaseNostrRepository +import at.torch.compose.database.repository.DatabaseSearchRepository import at.torch.compose.ui.composable.ActiveProfileScreen import at.torch.compose.ui.composable.ChatRoomCreationScreen import at.torch.compose.ui.composable.ChatRoomDetailScreen import at.torch.compose.ui.composable.HomeScreen +import at.torch.compose.ui.composable.ImplementationPendingScreen import at.torch.compose.ui.composable.KeyPackageManagementScreen import at.torch.compose.ui.composable.NostrEventDetailScreen +import at.torch.compose.ui.composable.SearchResultScreen +import at.torch.compose.ui.composable.SearchScreen import at.torch.compose.ui.composable.ShareProfileScreen +import at.torch.compose.ui.composable.SignInToProfileScreen +import at.torch.compose.ui.composable.SocialPreconditionScreen +import at.torch.compose.ui.composable.UnannouncedProfileScreen +import at.torch.compose.ui.composable.UnindexedProfileScreen +import at.torch.compose.ui.composable.UnqueuedProfileScreen +import at.torch.compose.ui.composable.UnqueuedProfileSynchronizationScreen +import at.torch.compose.ui.composable.UnsignedProfileScreen import at.torch.compose.ui.composable.UnsyncedProfileScreen +import at.torch.compose.ui.composable.WriteNewNoteScreen import at.torch.compose.ui.composable.navigation.routes.ActiveProfileRoute +import at.torch.compose.ui.composable.navigation.routes.BlankRoute import at.torch.compose.ui.composable.navigation.routes.ChatRoomCreationRoute import at.torch.compose.ui.composable.navigation.routes.ChatRoomDetailRoute +import at.torch.compose.ui.composable.navigation.routes.CreateProfileRoute +import at.torch.compose.ui.composable.navigation.routes.FeedRoute +import at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute import at.torch.compose.ui.composable.navigation.routes.KeyPackageManagementRoute +import at.torch.compose.ui.composable.navigation.routes.LandingRoute import at.torch.compose.ui.composable.navigation.routes.LoadingRoute import at.torch.compose.ui.composable.navigation.routes.NostrEventDetailRoute +import at.torch.compose.ui.composable.navigation.routes.SearchResultRoute +import at.torch.compose.ui.composable.navigation.routes.SearchRoute import at.torch.compose.ui.composable.navigation.routes.ShareProfileRoute +import at.torch.compose.ui.composable.navigation.routes.SignInRoute import at.torch.compose.ui.composable.navigation.routes.SocialPreconditionRoute import at.torch.compose.ui.composable.navigation.routes.SovereignWalletStartupRoute +import at.torch.compose.ui.composable.navigation.routes.UnannouncedProfileRoute +import at.torch.compose.ui.composable.navigation.routes.UnindexedProfileRoute +import at.torch.compose.ui.composable.navigation.routes.UnqueuedProfileRoute +import at.torch.compose.ui.composable.navigation.routes.UnqueuedProfileSynchronizationRoute +import at.torch.compose.ui.composable.navigation.routes.UnsignedProfileRoute +import at.torch.compose.ui.composable.navigation.routes.UnsyncedProfileRoute import at.torch.compose.ui.composable.navigation.routes.WriteNewNoteRoute +import at.torch.compose.ui.view.model.NavigationViewModel +import at.torch.compose.ui.view.model.NotaryViewModel +import at.torch.compose.ui.view.model.SovereignWalletViewModel +import at.torch.compose.ui.view.model.SynchronizationViewModel import at.torch.compose.ui.view.state.NavigationUIState +import at.torch.compose.ui.view.state.NostrEventDetailUIState +import at.torch.compose.ui.view.state.SearchUIState import co.touchlab.kermit.Logger import fr.acinq.phoenix.PhoenixGlobal import kotlinx.coroutines.CoroutineExceptionHandler @@ -43,16 +78,15 @@ import kotlinx.coroutines.launch @Composable fun TorchNavHost( - torchGlobal: at.torch.compose.TorchGlobal, + torchGlobal: TorchGlobal, phoenixGlobal: PhoenixGlobal, navController: NavHostController ) { val logger = Logger.withTag("AuxNavHost") -// TODO - val exceptionHandler = - CoroutineExceptionHandler { _, throwable -> - logger.e("Caught exception: ${throwable.message}", throwable) - } + + val exceptionHandler = CoroutineExceptionHandler { _, throwable -> + logger.e("Caught exception: ${throwable.message}", throwable) + } val applicationIOScope = CoroutineScope(Dispatchers.IO + SupervisorJob() + exceptionHandler) val applicationMainScope = CoroutineScope(Dispatchers.Main) @@ -62,33 +96,33 @@ fun TorchNavHost( val auxDatabaseManager = at.torch.compose.managers.AuxDatabaseManager(torchGlobal) - val databaseNostrRepository = - at.torch.compose.database.repository.DatabaseNostrRepository( - database = auxDatabaseManager.auxDatabase, - applicationIOScope - ) - val databaseChatRepository = - at.torch.compose.database.repository.DatabaseChatRepository( - database = auxDatabaseManager.auxDatabase, - applicationIOScope - ) + val databaseNostrRepository = DatabaseNostrRepository( + database = auxDatabaseManager.auxDatabase, + applicationIOScope + ) + + val databaseChatRepository = DatabaseChatRepository( + database = auxDatabaseManager.auxDatabase, + applicationIOScope + ) val databaseMarmotRepository = DatabaseMarmotRepository( database = auxDatabaseManager.auxDatabase, applicationIOScope ) - val searchRepository = - at.torch.compose.database.repository.DatabaseSearchRepository( - database = auxDatabaseManager.auxDatabase + val searchRepository = DatabaseSearchRepository( + database = auxDatabaseManager.auxDatabase + ) + + val sovereignWalletViewModel: SovereignWalletViewModel = viewModel( + factory = SovereignWalletViewModel.factory( + phoenixGlobal = phoenixGlobal ) + ) - val sovereignWalletViewModel: at.torch.compose.ui.view.model.SovereignWalletViewModel = viewModel(factory = at.torch.compose.ui.view.model.SovereignWalletViewModel.factory( - phoenixGlobal = phoenixGlobal - )) - - val navigationViewModel: at.torch.compose.ui.view.model.NavigationViewModel = viewModel ( - factory = at.torch.compose.ui.view.model.NavigationViewModel.factory( + val navigationViewModel: NavigationViewModel = viewModel ( + factory = NavigationViewModel.factory( activeWallet = sovereignWalletViewModel.activeWalletInUI, initialNavigationUIState = NavigationUIState.Loading(), nostrRepository = databaseNostrRepository, @@ -96,9 +130,8 @@ fun TorchNavHost( ) ) - - val notaryViewModel: at.torch.compose.ui.view.model.NotaryViewModel = viewModel( - factory = at.torch.compose.ui.view.model.NotaryViewModel.factory( + val notaryViewModel: NotaryViewModel = viewModel( + factory = NotaryViewModel.factory( activeWalletStateFlow = sovereignWalletViewModel.activeWalletInUI, nostrRepository = databaseNostrRepository, chatRepository = databaseChatRepository, @@ -108,8 +141,8 @@ fun TorchNavHost( ) // TODO: Produce a notary UI Element... - val synchronizationViewModel: at.torch.compose.ui.view.model.SynchronizationViewModel = viewModel( - factory = at.torch.compose.ui.view.model.SynchronizationViewModel.factory( + val synchronizationViewModel: SynchronizationViewModel = viewModel( + factory = SynchronizationViewModel.factory( activeWalletStateFlow = sovereignWalletViewModel.activeWalletInUI, nostrRepository = databaseNostrRepository, chatRepository = databaseChatRepository, @@ -117,6 +150,7 @@ fun TorchNavHost( scope = applicationIOScope ) ) + // TODO: Produce a synchronization UI element... LaunchedEffect(lifecycleOwner) { @@ -124,7 +158,7 @@ fun TorchNavHost( when (state) { is NavigationUIState.Error -> { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute( + route = ImplementationPendingRoute( "Error screen" ) ) { @@ -149,14 +183,14 @@ fun TorchNavHost( } is NavigationUIState.Landing -> { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.LandingRoute + route = LandingRoute ) { popUpTo(0) } } is NavigationUIState.UnsignedProfile -> { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.UnsignedProfileRoute( + route = UnsignedProfileRoute( state.unsignedNostrEvent.id ) ) { @@ -165,7 +199,7 @@ fun TorchNavHost( } is NavigationUIState.UnsyncedProfile -> { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.UnsyncedProfileRoute( + route = UnsyncedProfileRoute( state.unsignedNostrEvent.pubKey ) ) { @@ -174,7 +208,7 @@ fun TorchNavHost( } is NavigationUIState.UnqueuedProfileSynchronization -> { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.UnqueuedProfileSynchronizationRoute( + route = UnqueuedProfileSynchronizationRoute( unsignedNostrEventId = state.unsignedNostrEvent.id, publicKey = state.unsignedNostrEvent.pubKey ) @@ -184,7 +218,7 @@ fun TorchNavHost( } is NavigationUIState.UnindexedProfile -> { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.UnindexedProfileRoute( + route = UnindexedProfileRoute( state.nostrEvent.id ) ) { @@ -193,14 +227,14 @@ fun TorchNavHost( } is NavigationUIState.UnqueuedProfile -> { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.UnqueuedProfileRoute( + route = UnqueuedProfileRoute( state.profile.nostrEventId ) ) } is NavigationUIState.UnannouncedProfile -> { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.UnannouncedProfileRoute( + route = UnannouncedProfileRoute( state.broadcastNostrEventRequest.nostrEventId ) ) { @@ -218,7 +252,7 @@ fun TorchNavHost( } else -> { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute( + route = ImplementationPendingRoute( "Unsupported $state" ) ) { @@ -270,32 +304,32 @@ fun TorchNavHost( text = route.text ) } - composable { + composable { at.torch.compose.ui.composable.LandingScreen( onNavigateToLearnMore = { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute( + route = ImplementationPendingRoute( "Learn more" ) ) }, onNavigateToSignIn = { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.SignInRoute + route = SignInRoute ) }, onNavigateToCreateProfile = { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.CreateProfileRoute() + route = CreateProfileRoute() ) } ) } - composable { + composable { at.torch.compose.ui.composable.CreateProfileScreen( onNavigateToEndThis = { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.BlankRoute + route = BlankRoute ) { popUpTo(0) } @@ -339,7 +373,7 @@ fun TorchNavHost( } composable { backStackEntry -> val route = backStackEntry.toRoute() - at.torch.compose.ui.composable.WriteNewNoteScreen( + WriteNewNoteScreen( replyToNostrEventId = route.inReplyToEventId, activeUserPublicKey = route.activeUserPublicKey, quotedNostrEventId = route.quotedEventId, @@ -359,69 +393,69 @@ fun TorchNavHost( nostrRepository = databaseNostrRepository ) } - composable { - at.torch.compose.ui.composable.SignInToProfileScreen( + composable { + SignInToProfileScreen( nostrRepository = databaseNostrRepository ) } - composable { backStackEntry -> - backStackEntry.toRoute() + composable { backStackEntry -> + backStackEntry.toRoute() - at.torch.compose.ui.composable.UnsignedProfileScreen() + UnsignedProfileScreen() } - composable { backStackEntry -> - val route = backStackEntry.toRoute() + composable { backStackEntry -> + val route = backStackEntry.toRoute() UnsyncedProfileScreen( unsyncedProfilePublicKey = route.publicKey ) } - composable { backStackEntry -> - val route = backStackEntry.toRoute() - at.torch.compose.ui.composable.UnqueuedProfileSynchronizationScreen( + composable { backStackEntry -> + val route = backStackEntry.toRoute() + UnqueuedProfileSynchronizationScreen( unsignedNostrEventId = route.unsignedNostrEventId, profilePublicKey = route.publicKey, nostrRepository = databaseNostrRepository ) } - composable { - at.torch.compose.ui.composable.UnindexedProfileScreen() + composable { + UnindexedProfileScreen() } - composable { - at.torch.compose.ui.composable.UnqueuedProfileScreen() + composable { + UnqueuedProfileScreen() } - composable { backStackEntry -> - backStackEntry.toRoute() + composable { backStackEntry -> + backStackEntry.toRoute() - at.torch.compose.ui.composable.UnannouncedProfileScreen() + UnannouncedProfileScreen() } composable { backStackEntry -> val route = backStackEntry.toRoute() - at.torch.compose.ui.composable.SocialPreconditionScreen( + SocialPreconditionScreen( onNavigateToSkipForNow = { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.FeedRoute( + route = FeedRoute( activeUserPublicKey = route.activeUserPubkey ) ) }, onNavigateToInviteFriend = { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute( + route = ImplementationPendingRoute( "Invite Friend" ) ) }, onNavigateToViewInvites = { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute( + route = ImplementationPendingRoute( "View invites" ) ) } ) } - composable { backStackEntry -> - val route = backStackEntry.toRoute() + composable { backStackEntry -> + val route = backStackEntry.toRoute() HomeScreen( activeUserPublicKey = route.activeUserPublicKey, onNavigateToEvent = { eventRoute -> @@ -438,7 +472,7 @@ fun TorchNavHost( }, onNavigateToSearch = { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.SearchRoute( + route = SearchRoute( activeUserPublicKey = route.activeUserPublicKey ) ) @@ -452,7 +486,7 @@ fun TorchNavHost( chatRepository = databaseChatRepository ) } - composable { + composable { Surface( modifier = Modifier.fillMaxSize(), color = Color.Black @@ -531,12 +565,12 @@ fun TorchNavHost( }, ) } - composable { backStackEntry -> - val route = backStackEntry.toRoute() + composable { backStackEntry -> + val route = backStackEntry.toRoute() - at.torch.compose.ui.composable.SearchScreen( + SearchScreen( activeUserPublicKey = route.activeUserPublicKey, - initialSearchUIState = at.torch.compose.ui.view.state.SearchUIState.Prompt, + initialSearchUIState = SearchUIState.Prompt, nostrRepository = databaseNostrRepository, searchRepository = searchRepository, onNavigateToProfile = { route -> @@ -551,10 +585,10 @@ fun TorchNavHost( } ) } - composable { backStackEntry -> - val route = backStackEntry.toRoute() + composable { backStackEntry -> + val route = backStackEntry.toRoute() - at.torch.compose.ui.composable.SearchResultScreen( + SearchResultScreen( activeUserPublicKey = route.activeUserPublicKey, searchQuery = route.query, nostrRepository = databaseNostrRepository, @@ -574,7 +608,7 @@ fun TorchNavHost( NostrEventDetailScreen( activeUserPublicKey = route.activeUserPublicKey, - initialNostrEventDetailUIState = at.torch.compose.ui.view.state.NostrEventDetailUIState.Loading, + initialNostrEventDetailUIState = NostrEventDetailUIState.Loading, nostrEventId = route.nostrEventId, nostrRepository = databaseNostrRepository, onNavigateBack = { @@ -595,7 +629,7 @@ fun TorchNavHost( }, onNavigateToEditProfile = { navController.navigate( - route = at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute( + route = ImplementationPendingRoute( "Edit Profile" ) ) @@ -619,9 +653,9 @@ fun TorchNavHost( }, ) } - composable { backStackEntry -> - val route: at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute = backStackEntry.toRoute() - at.torch.compose.ui.composable.ImplementationPendingScreen( + composable { backStackEntry -> + val route: ImplementationPendingRoute = backStackEntry.toRoute() + ImplementationPendingScreen( route.name ) } diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/widgets/detail/MetadataEventDetail.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/widgets/detail/MetadataEventDetail.kt index 0bb8c63c..ecd90a7a 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/widgets/detail/MetadataEventDetail.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/composable/widgets/detail/MetadataEventDetail.kt @@ -46,8 +46,18 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel +import at.torch.compose.database.model.NostrEvent +import at.torch.compose.database.model.Profile +import at.torch.compose.database.model.intermdiate.LocalNostrEvent +import at.torch.compose.repository.NostrRepository import at.torch.compose.ui.composable.navigation.routes.ChatRoomDetailRoute import at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute +import at.torch.compose.ui.composable.navigation.routes.Route +import at.torch.compose.ui.composable.widgets.profile.ProfileAvatar +import at.torch.compose.ui.theme.TorchTheme +import at.torch.compose.ui.view.model.MetadataEventDetailType +import at.torch.compose.ui.view.model.MetadataEventDetailViewModel +import at.torch.compose.ui.view.state.MetadataEventDetailUIState import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent import kotlinx.coroutines.launch @@ -55,25 +65,25 @@ import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun MetadataEventDetail( - localNostrEvent: at.torch.compose.database.model.intermdiate.LocalNostrEvent, + localNostrEvent: LocalNostrEvent, activeUserPublicKey: HexKey, onNavigateBack: () -> Unit, - onNavigateToEvent: (at.torch.compose.ui.composable.navigation.routes.Route) -> Unit, + onNavigateToEvent: (Route) -> Unit, onNavigateToEditProfile: () -> Unit, - onNavigateToChatRoom: (at.torch.compose.ui.composable.navigation.routes.Route) -> Unit, - nostrRepository: at.torch.compose.repository.NostrRepository + onNavigateToChatRoom: (Route) -> Unit, + nostrRepository: NostrRepository ) { val scope = rememberCoroutineScope() val profile = localNostrEvent.profile val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState()) - val metadataEventDetailViewModel: at.torch.compose.ui.view.model.MetadataEventDetailViewModel = viewModel( - factory = at.torch.compose.ui.view.model.MetadataEventDetailViewModel.factory( + val metadataEventDetailViewModel: MetadataEventDetailViewModel = viewModel( + factory = MetadataEventDetailViewModel.factory( activeUserPublicKey = activeUserPublicKey, publicKey = localNostrEvent.nostrEvent.pubKey, nostrRepository = nostrRepository, - pagerState = rememberPagerState { at.torch.compose.ui.view.model.MetadataEventDetailType.entries.size } + pagerState = rememberPagerState { MetadataEventDetailType.entries.size } ), ) @@ -146,7 +156,7 @@ fun MetadataEventDetail( horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically ) { - _root_ide_package_.at.torch.compose.ui.composable.widgets.profile.ProfileAvatar( + ProfileAvatar( size = 75.dp, profile = profile, publicKey = localNostrEvent.nostrEvent.pubKey @@ -158,13 +168,13 @@ fun MetadataEventDetail( ) when(val metadataEventDetailUIState = metadataEventDetailViewModel.metadataEventDetailUIState) { - at.torch.compose.ui.view.state.MetadataEventDetailUIState.Error -> { + MetadataEventDetailUIState.Error -> { Icon( Icons.Default.Error, contentDescription = "Something went wrong" ) } - is at.torch.compose.ui.view.state.MetadataEventDetailUIState.Loaded -> { + is MetadataEventDetailUIState.Loaded -> { if (metadataEventDetailViewModel.isActionPending.value) { LoadingIndicator() @@ -211,7 +221,7 @@ fun MetadataEventDetail( } - at.torch.compose.ui.view.state.MetadataEventDetailUIState.Loading -> { + MetadataEventDetailUIState.Loading -> { LoadingIndicator() } } @@ -306,14 +316,14 @@ fun MetadataEventDetail( @Composable private fun MetadataEventEventDetailPreview() { - _root_ide_package_.at.torch.compose.ui.theme.TorchTheme { + TorchTheme { Surface( modifier = Modifier.padding(20.dp) ) { MetadataEventDetail( activeUserPublicKey = "", - localNostrEvent = _root_ide_package_.at.torch.compose.database.model.intermdiate.LocalNostrEvent( - nostrEvent = _root_ide_package_.at.torch.compose.database.model.NostrEvent( + localNostrEvent = LocalNostrEvent( + nostrEvent = NostrEvent( id = "eventId", pubKey = "publicKey", content = """Profile""".trimIndent(), @@ -321,7 +331,7 @@ private fun MetadataEventEventDetailPreview() { sig = "", kind = MetadataEvent.KIND ), - profile = _root_ide_package_.at.torch.compose.database.model.Profile( + profile = Profile( publicKey = "pubKey", displayName = "John Doe", nip05 = "john@doe.com", @@ -333,7 +343,7 @@ private fun MetadataEventEventDetailPreview() { onNavigateToEvent = {}, onNavigateToEditProfile = {}, onNavigateToChatRoom = {}, - nostrRepository = at.torch.compose.repository.NostrRepository.NO_OP_NOSTR_REPOSITORY + nostrRepository = NostrRepository.NO_OP_NOSTR_REPOSITORY ) } } diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/ChatRoomDetailMessageListViewModel.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/ChatRoomDetailMessageListViewModel.kt index 01df92c0..acf029ab 100755 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/ChatRoomDetailMessageListViewModel.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/ChatRoomDetailMessageListViewModel.kt @@ -43,9 +43,13 @@ import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import at.torch.compose.database.model.NegentropySynchronizeRequest +import at.torch.compose.database.model.intermdiate.LocalChatRoom import at.torch.compose.database.model.types.SynchronizationFilter import at.torch.compose.extensions.toFormattedTimeAndDateString import at.torch.compose.nostr.Relays +import at.torch.compose.repository.ChatRepository +import at.torch.compose.repository.NostrRepository +import at.torch.compose.ui.composable.widgets.profile.ProfileColor import at.torch.compose.ui.view.state.ChatRoomDetailMessageListUIState import co.touchlab.kermit.Logger import com.vitorpamplona.quartz.nip17Dm.settings.ChatMessageRelayListEvent @@ -57,9 +61,9 @@ import kotlinx.coroutines.launch class ChatRoomDetailMessageListViewModel( initialChatRoomDetailMessageListUIState: ChatRoomDetailMessageListUIState, - val localChatRoom: at.torch.compose.database.model.intermdiate.LocalChatRoom, - val nostrRepository: at.torch.compose.repository.NostrRepository, - val chatRepository: at.torch.compose.repository.ChatRepository + val localChatRoom: LocalChatRoom, + val nostrRepository: NostrRepository, + val chatRepository: ChatRepository ): ViewModel() { val logger = Logger.withTag(TAG) var chatRoomDetailMessageListUIState: ChatRoomDetailMessageListUIState by mutableStateOf(initialChatRoomDetailMessageListUIState) @@ -290,7 +294,7 @@ class ChatRoomDetailMessageListViewModel( text = localChatMessage.profile?.humanReadableNameOrPubkey() ?: localChatMessage.chatMessage.senderPublicKey, maxLines = 1, overflow = TextOverflow.MiddleEllipsis, - color = at.torch.compose.ui.composable.widgets.profile.ProfileColor.fromPublicKey(localChatMessage.chatMessage.senderPublicKey), + color = ProfileColor.fromPublicKey(localChatMessage.chatMessage.senderPublicKey), style = MaterialTheme.typography.labelSmall ) } @@ -389,9 +393,9 @@ class ChatRoomDetailMessageListViewModel( fun factory( initialChatRoomDetailMessageListUIState: ChatRoomDetailMessageListUIState = ChatRoomDetailMessageListUIState.Loading, - localChatRoom: at.torch.compose.database.model.intermdiate.LocalChatRoom, - nostrRepository: at.torch.compose.repository.NostrRepository, - chatRepository: at.torch.compose.repository.ChatRepository + localChatRoom: LocalChatRoom, + nostrRepository: NostrRepository, + chatRepository: ChatRepository ): ViewModelProvider.Factory = viewModelFactory { initializer { ChatRoomDetailMessageListViewModel( diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/ChatRoomDetailViewModel.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/ChatRoomDetailViewModel.kt index 98cc5268..417158f2 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/ChatRoomDetailViewModel.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/ChatRoomDetailViewModel.kt @@ -10,6 +10,7 @@ import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import at.torch.compose.repository.ChatRepository +import at.torch.compose.repository.NostrRepository import at.torch.compose.ui.composable.navigation.routes.ChatRoomDetailRoute import at.torch.compose.ui.composable.navigation.routes.Route import at.torch.compose.ui.view.state.ChatRoomDetailUIState @@ -25,7 +26,7 @@ class ChatRoomDetailViewModel( val activeUserPublicKey: HexKey, val relayHint: String?, initialChatRoomDetailUIState: ChatRoomDetailUIState, - val nostrRepository: at.torch.compose.repository.NostrRepository, + val nostrRepository: NostrRepository, val chatRepository: ChatRepository ): ViewModel() { @@ -135,7 +136,7 @@ class ChatRoomDetailViewModel( chatRoomId: String, relayHint: String?, initialChatRoomDetailUIState: ChatRoomDetailUIState = ChatRoomDetailUIState.Loading, - nostrRepository: at.torch.compose.repository.NostrRepository, + nostrRepository: NostrRepository, chatRepository: ChatRepository ): ViewModelProvider.Factory = viewModelFactory { initializer { diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/state/ChatRoomDetailUIState.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/state/ChatRoomDetailUIState.kt index b3446ab0..8e7a2863 100755 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/state/ChatRoomDetailUIState.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/state/ChatRoomDetailUIState.kt @@ -1,8 +1,10 @@ package at.torch.compose.ui.view.state +import at.torch.compose.database.model.intermdiate.LocalChatRoom + sealed interface ChatRoomDetailUIState { data class Loaded( - val localChatRoom: at.torch.compose.database.model.intermdiate.LocalChatRoom + val localChatRoom: LocalChatRoom ): ChatRoomDetailUIState data class Error(