From 6c923a1b683b6ea3189e7545a150468398f27ace Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Sat, 6 Jun 2026 10:40:23 +0700 Subject: [PATCH] add update profile function --- .../su/reya/coop/screens/UpdateProfile.kt | 2 +- .../commonMain/kotlin/su/reya/coop/Nostr.kt | 39 ++++++++++ .../kotlin/su/reya/coop/NostrViewModel.kt | 73 ++++++++++++------- 3 files changed, 88 insertions(+), 26 deletions(-) diff --git a/composeApp/src/androidMain/kotlin/su/reya/coop/screens/UpdateProfile.kt b/composeApp/src/androidMain/kotlin/su/reya/coop/screens/UpdateProfile.kt index e45eca5..5bf03ae 100644 --- a/composeApp/src/androidMain/kotlin/su/reya/coop/screens/UpdateProfile.kt +++ b/composeApp/src/androidMain/kotlin/su/reya/coop/screens/UpdateProfile.kt @@ -32,7 +32,7 @@ fun UpdateProfileScreen() { onBack = { navigator.goBack() }, onConfirm = { name, bio, bytes, type -> scope.launch { - //viewModel.updateProfile(name, bio, bytes, type) + viewModel.updateProfile(name, bio, bytes, type) navigator.goBack() } } diff --git a/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt b/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt index 82c578f..9874fd2 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/Nostr.kt @@ -498,6 +498,45 @@ class Nostr { setSigner(keys) } + suspend fun updateProfile( + name: String? = null, + bio: String? = null, + picture: String? = null + ) { + val currentUser = signer.currentUser ?: throw IllegalStateException("User not signed in") + + try { + val record = getLatestMetadata(currentUser)?.asRecord() ?: MetadataRecord() + val newRecord = record.copy( + displayName = name ?: record.displayName, + about = bio ?: record.about, + picture = picture ?: record.picture + ) + val event = EventBuilder.metadata(Metadata.fromRecord(newRecord)).signAsync(signer) + + client?.sendEvent( + event = event, + target = SendEventTarget.broadcast(), + ackPolicy = AckPolicy.none() + ) + } catch (e: Exception) { + throw IllegalStateException("Failed to update identity: ${e.message}", e) + } + } + + private suspend fun getLatestMetadata(pubkey: PublicKey): Metadata? { + return try { + val kind = Kind.fromStd(KindStandard.METADATA); + val filter = Filter().kind(kind).author(pubkey).limit(1u) + val event = client?.database()?.query(filter)?.first() ?: return null + + Metadata.fromJson(event.content()) + } catch (e: Exception) { + println("Failed to get latest metadata: ${e.message}") + null + } + } + suspend fun getAllCacheMetadata(): Map { try { val filter = Filter().kind(Kind.fromStd(KindStandard.METADATA)).limit(100u) diff --git a/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt b/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt index a5fbb77..75f3c37 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/NostrViewModel.kt @@ -344,6 +344,53 @@ class NostrViewModel( } } + private suspend fun blossomUpload(file: ByteArray, contentType: String): String? { + try { + var avatarUrl: String? = null + + // Upload picture to Blossom + val blossom = BlossomClient( + url = "https://blossom.band", + client = HttpClient { + install(ContentNegotiation) { + json(Json { + ignoreUnknownKeys = true + prettyPrint = true + isLenient = true + }) + } + } + ) + + val descriptor = blossom.upload( + file = file, + contentType = contentType, + signer = nostr.signer + ) + + avatarUrl = descriptor?.url + + return avatarUrl + } catch (e: Exception) { + showError("Error: ${e.message}") + return null + } + } + + suspend fun updateProfile( + name: String? = null, + bio: String? = null, + picture: ByteArray? = null, + contentType: String? = null + ) { + try { + val avatarUrl = picture?.let { blossomUpload(it, contentType ?: "image/jpeg") } + nostr.updateProfile(name, bio, avatarUrl) + } catch (e: Exception) { + showError("Error: ${e.message}") + } + } + suspend fun createIdentity( name: String, bio: String?, @@ -354,31 +401,7 @@ class NostrViewModel( try { val keys = Keys.generate() val secret = keys.secretKey().toBech32() - var avatarUrl = "" - - // Upload picture to Blossom - if (picture != null) { - val blossom = BlossomClient( - url = "https://blossom.band", - client = HttpClient { - install(ContentNegotiation) { - json(Json { - ignoreUnknownKeys = true - prettyPrint = true - isLenient = true - }) - } - } - ) - - val descriptor = blossom.upload( - file = picture, - contentType = contentType, - signer = keys - ) - - avatarUrl = descriptor?.url ?: "" - } + val avatarUrl = picture?.let { blossomUpload(it, contentType ?: "image/jpeg") } // Create identity nostr.createIdentity(keys = keys, name = name, bio, picture = avatarUrl)