diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 3cb24e19a..978bbc38a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -39,7 +39,7 @@ class Account( ) { fun userProfile(): User { - return LocalCache.getOrCreateUser(loggedIn.pubKey) + return LocalCache.getOrCreateUser(loggedIn.pubKey.toHexKey()) } fun followingChannels(): List { @@ -47,7 +47,7 @@ class Account( } fun hiddenUsers(): List { - return hiddenUsers.map { LocalCache.getOrCreateUser(it.toByteArray()) } + return hiddenUsers.map { LocalCache.getOrCreateUser(it) } } fun isWriteable(): Boolean { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt index 48b6b47f0..1f9448005 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt @@ -17,6 +17,10 @@ class Channel(val id: ByteArray) { val notes = ConcurrentHashMap() + fun toBestDisplayName(): String { + return info.name ?: idDisplayHex + } + @Synchronized fun addNote(note: Note) { notes[note.idHex] = note diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Hex.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Hex.kt index 5fddc4ce4..e57047d2b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Hex.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Hex.kt @@ -11,6 +11,17 @@ import nostr.postr.toHex /** Makes the distinction between String and Hex **/ typealias HexKey = String +typealias NPubKey = String +typealias NoteId = String + +fun NPubKey.toDisplayKey(): String { + return this.toShortenHex() +} + +fun NoteId.toDisplayId(): String { + return this.toShortenHex() +} + fun ByteArray.toNote() = Bech32.encodeBytes(hrp = "note", this, Bech32.Encoding.Bech32) fun ByteArray.toHexKey(): HexKey { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt index 399aedf0c..a87d8eeef 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -41,10 +41,9 @@ object LocalCache { val channels = ConcurrentHashMap() @Synchronized - fun getOrCreateUser(pubkey: ByteArray): User { - val key = pubkey.toHexKey() + fun getOrCreateUser(key: HexKey): User { return users[key] ?: run { - val answer = User(pubkey) + val answer = User(key) users.put(key, answer) answer } @@ -71,7 +70,7 @@ object LocalCache { fun consume(event: MetadataEvent) { // new event - val oldUser = getOrCreateUser(event.pubKey) + val oldUser = getOrCreateUser(event.pubKey.toHexKey()) if (event.createdAt > oldUser.updatedMetadataAt) { //Log.d("MT", "New User ${users.size} ${event.contactMetaData.name}") @@ -98,7 +97,7 @@ object LocalCache { fun consume(event: TextNoteEvent, relay: Relay? = null) { val note = getOrCreateNote(event.id.toHex()) - val author = getOrCreateUser(event.pubKey) + val author = getOrCreateUser(event.pubKey.toHexKey()) if (relay != null) author.addRelay(relay, event.createdAt) @@ -106,7 +105,7 @@ object LocalCache { // Already processed this event. if (note.event != null) return - val mentions = Collections.synchronizedList(event.mentions.map { getOrCreateUser(decodePublicKey(it)) }) + val mentions = Collections.synchronizedList(event.mentions.map { getOrCreateUser(it) }) val replyTo = Collections.synchronizedList(event.replyTos.map { getOrCreateNote(it) }.toMutableList()) note.loadEvent(event, author, mentions, replyTo) @@ -137,7 +136,7 @@ object LocalCache { } fun consume(event: ContactListEvent) { - val user = getOrCreateUser(event.pubKey) + val user = getOrCreateUser(event.pubKey.toHexKey()) if (event.createdAt > user.updatedFollowsAt) { //Log.d("CL", "AAA ${user.toBestDisplayName()} ${event.follows.size}") @@ -145,7 +144,7 @@ object LocalCache { event.follows.map { try { val pubKey = decodePublicKey(it.pubKeyHex) - getOrCreateUser(pubKey) + getOrCreateUser(pubKey.toHexKey()) } catch (e: Exception) { println("Could not parse Hex key: ${it.pubKeyHex}") println("UpdateFollows: " + event.toJson()) @@ -179,13 +178,13 @@ object LocalCache { // Already processed this event. if (note.event != null) return - val author = getOrCreateUser(event.pubKey) - val recipient = event.recipientPubKey?.let { getOrCreateUser(it) } + val author = getOrCreateUser(event.pubKey.toHexKey()) + val recipient = event.recipientPubKey?.let { getOrCreateUser(it.toHexKey()) } //Log.d("PM", "${author.toBestDisplayName()} to ${recipient?.toBestDisplayName()}") val repliesTo = event.tags.filter { it.firstOrNull() == "e" }.mapNotNull { it.getOrNull(1) }.map { getOrCreateNote(it) }.toMutableList() - val mentions = event.tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }.map { getOrCreateUser(decodePublicKey(it)) } + val mentions = event.tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }.map { getOrCreateUser(it) } note.loadEvent(event, author, mentions, repliesTo) @@ -209,8 +208,8 @@ object LocalCache { //Log.d("TN", "New Boost (${notes.size},${users.size}) ${note.author?.toBestDisplayName()} ${formattedDateTime(event.createdAt)}") - val author = getOrCreateUser(event.pubKey) - val mentions = event.originalAuthor.map { getOrCreateUser(decodePublicKey(it)) }.toList() + val author = getOrCreateUser(event.pubKey.toHexKey()) + val mentions = event.originalAuthor.map { getOrCreateUser(it) }.toList() val repliesTo = event.boostedPost.map { getOrCreateNote(it) }.toMutableList() note.loadEvent(event, author, mentions, repliesTo) @@ -235,13 +234,13 @@ object LocalCache { } fun consume(event: ReactionEvent) { - val note = getOrCreateNote(event.id.toHex()) + val note = getOrCreateNote(event.id.toHexKey()) // Already processed this event. if (note.event != null) return - val author = getOrCreateUser(event.pubKey) - val mentions = event.originalAuthor.map { getOrCreateUser(decodePublicKey(it)) } + val author = getOrCreateUser(event.pubKey.toHexKey()) + val mentions = event.originalAuthor.map { getOrCreateUser(it) } val repliesTo = event.originalPost.map { getOrCreateNote(it) }.toMutableList() note.loadEvent(event, author, mentions, repliesTo) @@ -285,8 +284,8 @@ object LocalCache { // Already processed this event. if (note.event != null) return - val author = getOrCreateUser(event.pubKey) - val mentions = event.reportedAuthor.map { getOrCreateUser(decodePublicKey(it)) } + val author = getOrCreateUser(event.pubKey.toHexKey()) + val mentions = event.reportedAuthor.map { getOrCreateUser(it) } val repliesTo = event.reportedPost.map { getOrCreateNote(it) }.toMutableList() note.loadEvent(event, author, mentions, repliesTo) @@ -305,7 +304,7 @@ object LocalCache { //Log.d("MT", "New Event ${event.content} ${event.id.toHex()}") // new event val oldChannel = getOrCreateChannel(event.id.toHex()) - val author = getOrCreateUser(event.pubKey) + val author = getOrCreateUser(event.pubKey.toHexKey()) if (event.createdAt > oldChannel.updatedMetadataAt) { if (oldChannel.creator == null || oldChannel.creator == author) { oldChannel.updateChannelInfo(author, event.channelInfo, event.createdAt) @@ -327,7 +326,7 @@ object LocalCache { // new event val oldChannel = getOrCreateChannel(event.channel) - val author = getOrCreateUser(event.pubKey) + val author = getOrCreateUser(event.pubKey.toHexKey()) if (event.createdAt > oldChannel.updatedMetadataAt) { if (oldChannel.creator == null || oldChannel.creator == author) { oldChannel.updateChannelInfo(author, event.channelInfo, event.createdAt) @@ -355,11 +354,18 @@ object LocalCache { // Already processed this event. if (note.event != null) return - val author = getOrCreateUser(event.pubKey) - val mentions = Collections.synchronizedList(event.mentions.map { getOrCreateUser(decodePublicKey(it)) }) + val author = getOrCreateUser(event.pubKey.toHexKey()) + val mentions = Collections.synchronizedList(event.mentions.map { getOrCreateUser(it) }) val replyTo = Collections.synchronizedList( event.replyTos - .map { getOrCreateNote(it) } + .mapNotNull { + try { + getOrCreateNote(it) + } catch (e: Exception) { + println("Failed to parse Key: $it") + null + } + } .filter { it.event !is ChannelCreateEvent } .toMutableList() ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt index 34cd6df36..278c5a70d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt @@ -5,6 +5,7 @@ import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.service.relays.Relay import com.vitorpamplona.amethyst.ui.note.toShortenHex +import fr.acinq.secp256k1.Hex import java.util.Collections import java.util.concurrent.ConcurrentHashMap import kotlinx.coroutines.CoroutineScope @@ -17,8 +18,8 @@ import nostr.postr.events.Event import nostr.postr.events.MetadataEvent import nostr.postr.toNpub -class User(val pubkey: ByteArray) { - val pubkeyHex = pubkey.toHexKey() +class User(val pubkeyHex: String) { + val pubkey = Hex.decode(pubkeyHex) val pubkeyDisplayHex = pubkey.toNpub().toShortenHex() var info = UserMetadata() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt index dccdb91e3..d37ea3474 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrUserProfileDataSource.kt @@ -14,7 +14,7 @@ object NostrUserProfileDataSource: NostrDataSource("UserProfileFeed") { var user: User? = null fun loadUserProfile(userId: String) { - user = LocalCache.getOrCreateUser(userId.toByteArray()) + user = LocalCache.getOrCreateUser(userId) resetFilters() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt index dc4277e72..bf344f984 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt @@ -16,6 +16,7 @@ import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.decodePublicKey +import com.vitorpamplona.amethyst.model.toHexKey import com.vitorpamplona.amethyst.ui.components.isValidURL import com.vitorpamplona.amethyst.ui.components.noProtocolUrlValidator import nostr.postr.toNpub @@ -78,7 +79,7 @@ class NewPostViewModel: ViewModel() { val restOfWord = word.substring(64) val key = decodePublicKey(keyB32.removePrefix("@")) - val user = LocalCache.getOrCreateUser(key) + val user = LocalCache.getOrCreateUser(key.toHexKey()) val index = addUserToMentionsIfNotInAndReturnIndex(user) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UrlUserTagTransformation.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UrlUserTagTransformation.kt index 50abf9a91..d4b4f2e5d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UrlUserTagTransformation.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UrlUserTagTransformation.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextDecoration import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.decodePublicKey +import com.vitorpamplona.amethyst.model.toHexKey import kotlin.math.roundToInt data class RangesChanges(val original: TextRange, val modified: TextRange) @@ -43,7 +44,7 @@ fun buildAnnotatedStringWithUrlHighlighting(text: AnnotatedString, color: Color) val endIndex = startIndex + keyB32.length val key = decodePublicKey(keyB32.removePrefix("@")) - val user = LocalCache.getOrCreateUser(key) + val user = LocalCache.getOrCreateUser(key.toHexKey()) val newWord = "@${user.toBestDisplayName()}" val startNew = builderAfter.toString().length