From 3d045fbf8dcfd2f612d6b206c34ce891241180b7 Mon Sep 17 00:00:00 2001 From: Kgothatso Ngako Date: Thu, 26 Mar 2026 03:03:42 +0200 Subject: [PATCH] Add pubKey to UnsignedNostrEvent.kt to support multi account. --- .../1.json | 12 ++++++++--- .../ac/aux/compose/database/dao/ProfileDao.kt | 2 +- .../database/model/UnsignedNostrEvent.kt | 1 + .../model/intermdiate/LocalProfile.kt | 9 ++++++++- .../repository/DatabaseNostrRepository.kt | 2 ++ .../ac/aux/compose/managers/SeedManager.kt | 16 +++++++++++++++ .../aux/compose/repository/NostrRepository.kt | 4 ++-- .../ui/view/model/CreateProfileViewModel.kt | 20 ++++++++----------- .../ui/view/model/NavigationViewModel.kt | 8 ++++---- 9 files changed, 51 insertions(+), 23 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/ac/aux/compose/managers/SeedManager.kt diff --git a/composeApp/schemas/ac.aux.compose.database.AuxDatabase/1.json b/composeApp/schemas/ac.aux.compose.database.AuxDatabase/1.json index 819ac83e..97ad3579 100644 --- a/composeApp/schemas/ac.aux.compose.database.AuxDatabase/1.json +++ b/composeApp/schemas/ac.aux.compose.database.AuxDatabase/1.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 1, - "identityHash": "80c7032502d17a1893ea8dc67debd365", + "identityHash": "3d48904218bb18d9efb6dba14449f27c", "entities": [ { "tableName": "BroadcastNostrEventReceipt", @@ -836,7 +836,7 @@ }, { "tableName": "UnsignedNostrEvent", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `kind` INTEGER NOT NULL, `tags` TEXT NOT NULL, `content` TEXT NOT NULL, `signedNostrEventId` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `deletedAt` INTEGER, `broadcastedAt` INTEGER, FOREIGN KEY(`signedNostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `pubKey` TEXT NOT NULL, `kind` INTEGER NOT NULL, `tags` TEXT NOT NULL, `content` TEXT NOT NULL, `signedNostrEventId` TEXT, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `deletedAt` INTEGER, `broadcastedAt` INTEGER, FOREIGN KEY(`signedNostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "fields": [ { "fieldPath": "id", @@ -844,6 +844,12 @@ "affinity": "INTEGER", "notNull": true }, + { + "fieldPath": "pubKey", + "columnName": "pubKey", + "affinity": "TEXT", + "notNull": true + }, { "fieldPath": "kind", "columnName": "kind", @@ -1095,7 +1101,7 @@ ], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '80c7032502d17a1893ea8dc67debd365')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '3d48904218bb18d9efb6dba14449f27c')" ] } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/dao/ProfileDao.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/dao/ProfileDao.kt index cff595b2..1b0e8d01 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/dao/ProfileDao.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/dao/ProfileDao.kt @@ -30,7 +30,7 @@ interface ProfileDao { @Upsert suspend fun upsert(profile: Profile) - @Query("SELECT * FROM NostrEvent WHERE kind = 0 AND pubKey = :publicKey") + @Query("SELECT * FROM UnsignedNostrEvent WHERE kind = 0 AND pubKey = :publicKey") fun observeProfile(publicKey: String): Flow } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/UnsignedNostrEvent.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/UnsignedNostrEvent.kt index aadbcb0d..c6b4db71 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/UnsignedNostrEvent.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/UnsignedNostrEvent.kt @@ -39,6 +39,7 @@ data class UnsignedNostrEvent( @PrimaryKey(autoGenerate = true) val id: Long = 0, + val pubKey: HexKey, val kind: Kind, val tags: TagArray, val content: String, diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/intermdiate/LocalProfile.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/intermdiate/LocalProfile.kt index 46415207..695a06db 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/intermdiate/LocalProfile.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/intermdiate/LocalProfile.kt @@ -2,11 +2,18 @@ package ac.aux.compose.database.model.intermdiate import ac.aux.compose.database.model.NostrEvent import ac.aux.compose.database.model.Profile +import ac.aux.compose.database.model.UnsignedNostrEvent import androidx.room.Embedded import androidx.room.Relation data class LocalProfile( - @Embedded val nostrEvent: NostrEvent, + @Embedded val unsignedNostrEvent: UnsignedNostrEvent, + + @Relation( + parentColumn = "signedNostrEventId", + entityColumn = "id" + ) + val nostrEvent: NostrEvent?, @Relation( parentColumn = "pubKey", diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/repository/DatabaseNostrRepository.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/repository/DatabaseNostrRepository.kt index 7f3cf1e7..f36b306b 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/repository/DatabaseNostrRepository.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/repository/DatabaseNostrRepository.kt @@ -20,6 +20,7 @@ class DatabaseNostrRepository( } override suspend fun createNewProfile( + publicKey: HexKey, name: String, biography: String, onError: () -> Unit, @@ -34,6 +35,7 @@ class DatabaseNostrRepository( val unsignedNostrEvent = saveUnsignedNostrEvent( UnsignedNostrEvent( + pubKey = publicKey, kind = profileEventTemplate.kind, createdAt = Instant.fromEpochMilliseconds(profileEventTemplate.createdAt), tags = profileEventTemplate.tags, diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/managers/SeedManager.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/managers/SeedManager.kt new file mode 100644 index 00000000..61cad396 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/managers/SeedManager.kt @@ -0,0 +1,16 @@ +package ac.aux.compose.managers + +import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair +import kotlin.random.Random + +object SeedManager { + + private val tempDevelopmentKeyPair = KeyPair( + privKey = Random(21_012_256L).nextBytes(32) + ) + + fun activePublicKey(): ByteArray { + // TODO: Actually set and get a pair... + return tempDevelopmentKeyPair.pubKey + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/repository/NostrRepository.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/repository/NostrRepository.kt index 619451e6..c1e4d9fc 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/repository/NostrRepository.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/repository/NostrRepository.kt @@ -1,11 +1,9 @@ package ac.aux.compose.repository -import ac.aux.compose.database.dao.ProfileDao import ac.aux.compose.database.model.NostrEvent import ac.aux.compose.database.model.Profile import ac.aux.compose.database.model.UnsignedNostrEvent import ac.aux.compose.database.model.intermdiate.LocalProfile -import ac.aux.compose.ui.view.state.CreateProfileUIState import com.vitorpamplona.quartz.nip01Core.core.HexKey import kotlinx.coroutines.flow.Flow @@ -13,6 +11,7 @@ interface NostrRepository { suspend fun observeProfile(publicKey: HexKey): Flow suspend fun createNewProfile( + publicKey: HexKey, name: String, biography: String, onError: () -> Unit, @@ -32,6 +31,7 @@ interface NostrRepository { } override suspend fun createNewProfile( + publicKey: HexKey, name: String, biography: String, onError: () -> Unit, diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/view/model/CreateProfileViewModel.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/view/model/CreateProfileViewModel.kt index 4f3300b8..b94d0bc6 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/view/model/CreateProfileViewModel.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/view/model/CreateProfileViewModel.kt @@ -1,8 +1,6 @@ package ac.aux.compose.ui.view.model -import ac.aux.compose.database.model.NostrEvent -import ac.aux.compose.database.model.Profile -import ac.aux.compose.database.model.UnsignedNostrEvent +import ac.aux.compose.managers.SeedManager import ac.aux.compose.repository.NostrRepository import ac.aux.compose.ui.view.state.CreateProfileUIState import androidx.compose.runtime.MutableState @@ -14,12 +12,10 @@ import androidx.lifecycle.viewmodel.viewModelFactory import ac.aux.compose.ui.view.state.form.CreateProfileFormState import androidx.lifecycle.viewModelScope import co.touchlab.kermit.Logger -import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent +import com.vitorpamplona.quartz.nip01Core.core.toHexKey import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.IO -import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import kotlin.time.Instant class CreateProfileViewModel( val initialCreateProfileUIState: CreateProfileUIState, @@ -75,6 +71,7 @@ class CreateProfileViewModel( viewModelScope.launch(Dispatchers.IO) { nostrRepository.createNewProfile( + SeedManager.activePublicKey().toHexKey(), name = createProfileFormState.nameField.text.value, biography = createProfileFormState.biographyField.text.value, onError = { @@ -91,13 +88,12 @@ class CreateProfileViewModel( createProfileUIState.value = CreateProfileUIState.UnbroadcastedProfile( nostrEvent = unbroadcastedNostrEvent, ) - }, - onProfileReady = { profile -> - createProfileUIState.value = CreateProfileUIState.ProfileReady( - profile = profile - ) } - ) + ) { profile -> + createProfileUIState.value = CreateProfileUIState.ProfileReady( + profile = profile + ) + } } } diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/view/model/NavigationViewModel.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/view/model/NavigationViewModel.kt index 415ddbf5..71350137 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/view/model/NavigationViewModel.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/view/model/NavigationViewModel.kt @@ -1,5 +1,6 @@ package ac.aux.compose.ui.view.model +import ac.aux.compose.managers.SeedManager import ac.aux.compose.repository.NostrRepository import ac.aux.compose.ui.view.state.NavigationUIState import androidx.lifecycle.ViewModel @@ -41,9 +42,6 @@ class NavigationViewModel( } } - val tempDevelopmentKeyPair = KeyPair( - privKey = Random(21_000_000L).nextBytes(32) - ) private val _navigationUIState = MutableStateFlow( initialNavigationUIState ) @@ -63,7 +61,9 @@ class NavigationViewModel( _navigationUIState.getAndUpdate { NavigationUIState.Landing } - nostrRepository.observeProfile(tempDevelopmentKeyPair.pubKey.toHexKey()).map { localProfile -> + nostrRepository.observeProfile( + publicKey = SeedManager.activePublicKey().toHexKey() + ).map { localProfile -> _navigationUIState.getAndUpdate { if (localProfile == null) { NavigationUIState.Landing