Clean up code for some of the imports

This commit is contained in:
Kgothatso Ngako
2026-07-06 13:13:37 +02:00
parent cb129bb0c6
commit aaf6bbad83
16 changed files with 268 additions and 184 deletions

View File

@@ -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<at.torch.compose.database.model.types.SynchronizationFilter>?): String? = try {
fun fromFilterArray(value: Array<SynchronizationFilter>?): String? = try {
return value?.let {
Json.encodeToString(value)
}
@@ -82,9 +83,9 @@ class TorchConverters {
}
@TypeConverter
fun toFilterArray(value: String?): Array<at.torch.compose.database.model.types.SynchronizationFilter>? = try {
fun toFilterArray(value: String?): Array<SynchronizationFilter>? = try {
return value?.let {
Json.decodeFromString<Array<at.torch.compose.database.model.types.SynchronizationFilter>>(it)
Json.decodeFromString<Array<SynchronizationFilter>>(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<at.torch.compose.database.model.types.SynchronizationFilter>(it)
Json.decodeFromString<SynchronizationFilter>(it)
}
} catch (e: Throwable) {
logger.e("Failed to convert to SynchronizationFilter $value", e)

View File

@@ -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<at.torch.compose.database.model.NegentropySynchronizeRequest?>
fun observeNegentropySynchronizeRequestsByStatus(status: String, createdAt: Instant = Clock.System.now()): Flow<NegentropySynchronizeRequest?>
@Query("SELECT COUNT(*) FROM NegentropySynchronizeRequest WHERE purpose = :purpose AND status IN (:status) AND createdAt > :createdAt")
fun observeNegentropySynchronizeRequestByPurposeAndStatusCount(purpose: String, status: List<String>, createdAt: Instant = Clock.System.now()): Flow<Int>
@Upsert
fun upsert(negentropySynchronizeRequest: at.torch.compose.database.model.NegentropySynchronizeRequest)
fun upsert(negentropySynchronizeRequest: NegentropySynchronizeRequest)
@Insert(
onConflict = IGNORE
)
fun insert(negentropySynchronizeRequests: List<at.torch.compose.database.model.NegentropySynchronizeRequest>)
fun insert(negentropySynchronizeRequests: List<NegentropySynchronizeRequest>)
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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")
}
} }

View File

@@ -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,
)

View File

@@ -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<List<at.torch.compose.database.model.intermdiate.LocalChatRoom>> {
override suspend fun observeChatRoomListByPublicKey(publicKey: String): Flow<List<LocalChatRoom>> {
return database.chatRoomDao().observeChatRoomListByUserPublicKey(publicKey)
}
override suspend fun getChatRoomListByPublicKey(publicKey: String): List<at.torch.compose.database.model.intermdiate.LocalChatRoom> {
override suspend fun getChatRoomListByPublicKey(publicKey: String): List<LocalChatRoom> {
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<Participant> {
return database.participantDao().findParticipantByPublicKey(publicKey)
}
override suspend fun getChatMessageListByChatRoomId(chatRoomId: String): List<at.torch.compose.database.model.intermdiate.LocalChatMessage> {
override suspend fun getChatMessageListByChatRoomId(chatRoomId: String): List<LocalChatMessage> {
return database.chatMessageDao().getChatMessagesByChatRoomId(chatRoomId)
}
override suspend fun observeChatMessageListByChatRoomId(chatRoomId: String): Flow<List<at.torch.compose.database.model.intermdiate.LocalChatMessage>> {
override suspend fun observeChatMessageListByChatRoomId(chatRoomId: String): Flow<List<LocalChatMessage>> {
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")

View File

@@ -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<at.torch.compose.database.model.GiftWrapPayload?>
suspend fun observeUnsealedGiftWrapPayloads(publicKey: HexKey): Flow<GiftWrapPayload?>
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<at.torch.compose.database.model.GiftWrapPayload?> {
override suspend fun observeUnsealedGiftWrapPayloads(publicKey: HexKey): Flow<GiftWrapPayload?> {
TODO("Not yet implemented")
}
override suspend fun sealGiftWrapPayload(
giftWrapPayload: at.torch.compose.database.model.GiftWrapPayload,
giftWrapPayload: GiftWrapPayload,
nostrSignerSync: NostrSignerSync
) {
TODO("Not yet implemented")

View File

@@ -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",

View File

@@ -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
)
}
}

View File

@@ -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 = {},

View File

@@ -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<at.torch.compose.ui.composable.navigation.routes.LandingRoute> {
composable<LandingRoute> {
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<at.torch.compose.ui.composable.navigation.routes.CreateProfileRoute> {
composable<CreateProfileRoute> {
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<WriteNewNoteRoute> { backStackEntry ->
val route = backStackEntry.toRoute<WriteNewNoteRoute>()
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.navigation.routes.SignInRoute> {
at.torch.compose.ui.composable.SignInToProfileScreen(
composable<SignInRoute> {
SignInToProfileScreen(
nostrRepository = databaseNostrRepository
)
}
composable<at.torch.compose.ui.composable.navigation.routes.UnsignedProfileRoute> { backStackEntry ->
backStackEntry.toRoute<at.torch.compose.ui.composable.navigation.routes.UnsignedProfileRoute>()
composable<UnsignedProfileRoute> { backStackEntry ->
backStackEntry.toRoute<UnsignedProfileRoute>()
at.torch.compose.ui.composable.UnsignedProfileScreen()
UnsignedProfileScreen()
}
composable<at.torch.compose.ui.composable.navigation.routes.UnsyncedProfileRoute> { backStackEntry ->
val route = backStackEntry.toRoute<at.torch.compose.ui.composable.navigation.routes.UnsyncedProfileRoute>()
composable<UnsyncedProfileRoute> { backStackEntry ->
val route = backStackEntry.toRoute<UnsyncedProfileRoute>()
UnsyncedProfileScreen(
unsyncedProfilePublicKey = route.publicKey
)
}
composable<at.torch.compose.ui.composable.navigation.routes.UnqueuedProfileSynchronizationRoute> { backStackEntry ->
val route = backStackEntry.toRoute<at.torch.compose.ui.composable.navigation.routes.UnqueuedProfileSynchronizationRoute>()
at.torch.compose.ui.composable.UnqueuedProfileSynchronizationScreen(
composable<UnqueuedProfileSynchronizationRoute> { backStackEntry ->
val route = backStackEntry.toRoute<UnqueuedProfileSynchronizationRoute>()
UnqueuedProfileSynchronizationScreen(
unsignedNostrEventId = route.unsignedNostrEventId,
profilePublicKey = route.publicKey,
nostrRepository = databaseNostrRepository
)
}
composable<at.torch.compose.ui.composable.navigation.routes.UnindexedProfileRoute> {
at.torch.compose.ui.composable.UnindexedProfileScreen()
composable<UnindexedProfileRoute> {
UnindexedProfileScreen()
}
composable<at.torch.compose.ui.composable.navigation.routes.UnqueuedProfileRoute> {
at.torch.compose.ui.composable.UnqueuedProfileScreen()
composable<UnqueuedProfileRoute> {
UnqueuedProfileScreen()
}
composable<at.torch.compose.ui.composable.navigation.routes.UnannouncedProfileRoute> { backStackEntry ->
backStackEntry.toRoute<at.torch.compose.ui.composable.navigation.routes.UnannouncedProfileRoute>()
composable<UnannouncedProfileRoute> { backStackEntry ->
backStackEntry.toRoute<UnannouncedProfileRoute>()
at.torch.compose.ui.composable.UnannouncedProfileScreen()
UnannouncedProfileScreen()
}
composable<SocialPreconditionRoute> { backStackEntry ->
val route = backStackEntry.toRoute<SocialPreconditionRoute>()
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<at.torch.compose.ui.composable.navigation.routes.FeedRoute> { backStackEntry ->
val route = backStackEntry.toRoute<at.torch.compose.ui.composable.navigation.routes.FeedRoute>()
composable<FeedRoute> { backStackEntry ->
val route = backStackEntry.toRoute<FeedRoute>()
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<at.torch.compose.ui.composable.navigation.routes.BlankRoute> {
composable<BlankRoute> {
Surface(
modifier = Modifier.fillMaxSize(),
color = Color.Black
@@ -531,12 +565,12 @@ fun TorchNavHost(
},
)
}
composable<at.torch.compose.ui.composable.navigation.routes.SearchRoute> { backStackEntry ->
val route = backStackEntry.toRoute<at.torch.compose.ui.composable.navigation.routes.SearchRoute>()
composable<SearchRoute> { backStackEntry ->
val route = backStackEntry.toRoute<SearchRoute>()
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<at.torch.compose.ui.composable.navigation.routes.SearchResultRoute> { backStackEntry ->
val route = backStackEntry.toRoute<at.torch.compose.ui.composable.navigation.routes.SearchResultRoute>()
composable<SearchResultRoute> { backStackEntry ->
val route = backStackEntry.toRoute<SearchResultRoute>()
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<at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute> { backStackEntry ->
val route: at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute = backStackEntry.toRoute()
at.torch.compose.ui.composable.ImplementationPendingScreen(
composable<ImplementationPendingRoute> { backStackEntry ->
val route: ImplementationPendingRoute = backStackEntry.toRoute()
ImplementationPendingScreen(
route.name
)
}

View File

@@ -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
)
}
}

View File

@@ -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(

View File

@@ -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 {

View File

@@ -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(