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 56d09a555..54b2dce55 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -194,27 +194,30 @@ class Account( return keyPair.privKey != null } - fun sendNewRelayList(relays: Map, signEvent: Boolean): ContactListEvent? { - if (!isWriteable() && signEvent) return null + fun sendNewRelayList(relays: Map) { + if (!isWriteable() && !loginWithAmber) return val contactList = userProfile().latestContactList if (contactList != null && contactList.tags.isNotEmpty()) { - val event = ContactListEvent.updateRelayList( + var event = ContactListEvent.updateRelayList( earlierVersion = contactList, relayUse = relays, keyPair = keyPair ) - if (!signEvent) { - return event + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = ContactListEvent.create(event, AmberUtils.content) } Client.send(event) LocalCache.consume(event) - return null } else { - val event = ContactListEvent.createFromScratch( + var event = ContactListEvent.createFromScratch( followUsers = listOf(), followTags = listOf(), followGeohashes = listOf(), @@ -224,28 +227,35 @@ class Account( keyPair = keyPair ) - if (!signEvent) { - return event + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = ContactListEvent.create(event, AmberUtils.content) } // Keep this local to avoid erasing a good contact list. // Client.send(event) LocalCache.consume(event) } - return null } - fun sendNewUserMetadata(toString: String, identities: List, signEvent: Boolean): MetadataEvent? { - if (!isWriteable() && signEvent) return null + fun sendNewUserMetadata(toString: String, identities: List) { + if (!isWriteable() && !loginWithAmber) return - val event = MetadataEvent.create(toString, identities, keyPair.pubKey.toHexKey(), keyPair.privKey) - if (!signEvent) { - return event + var event = MetadataEvent.create(toString, identities, keyPair.pubKey.toHexKey(), keyPair.privKey) + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = MetadataEvent.create(event, AmberUtils.content) } Client.send(event) LocalCache.consume(event) - return null + return } fun reactionTo(note: Note, reaction: String): List { @@ -264,15 +274,15 @@ class Account( return note.hasReacted(userProfile(), reaction) } - fun reactTo(note: Note, reaction: String, signEvent: Boolean): ReactionEvent? { - if (!isWriteable() && signEvent) return null + fun reactTo(note: Note, reaction: String) { + if (!isWriteable() && !loginWithAmber) return if (hasReacted(note, reaction)) { // has already liked this note - return null + return } - if (note.event is ChatMessageEvent && signEvent) { + if (note.event is ChatMessageEvent && !loginWithAmber) { val event = note.event as ChatMessageEvent val users = event.recipientsPubKey().plus(event.pubKey).toSet().toList() @@ -290,7 +300,7 @@ class Account( broadcastPrivately(giftWraps) } - return null + return } } @@ -304,35 +314,42 @@ class Account( broadcastPrivately(giftWraps) } - return null + return } else { if (reaction.startsWith(":")) { val emojiUrl = EmojiUrl.decode(reaction) if (emojiUrl != null) { note.event?.let { - val event = ReactionEvent.create(emojiUrl, it, keyPair) - if (!signEvent) { - return event + var event = ReactionEvent.create(emojiUrl, it, keyPair) + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = ReactionEvent.create(event, AmberUtils.content) } Client.send(event) LocalCache.consume(event) } - return null + return } } note.event?.let { - val event = ReactionEvent.create(reaction, it, keyPair) - if (!signEvent) { - return event + var event = ReactionEvent.create(reaction, it, keyPair) + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = ReactionEvent.create(event, AmberUtils.content) } Client.send(event) LocalCache.consume(event) } } - return null } fun createZapRequestFor(note: Note, pollOption: Int?, message: String = "", zapType: LnZapEvent.ZapType): LnZapRequestEvent? { @@ -539,61 +556,76 @@ class Account( LocalCache.consume(event, null) } - fun delete(note: Note, signEvent: Boolean): DeletionEvent? { - return delete(listOf(note), signEvent) + fun delete(note: Note) { + return delete(listOf(note)) } - fun delete(notes: List, signEvent: Boolean): DeletionEvent? { - if (!isWriteable() && signEvent) return null + fun delete(notes: List) { + if (!isWriteable() && !loginWithAmber) return val myNotes = notes.filter { it.author == userProfile() }.map { it.idHex } if (myNotes.isNotEmpty()) { - val event = DeletionEvent.create(myNotes, keyPair) - if (!signEvent) { - return event + var event = DeletionEvent.create(myNotes, keyPair) + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = DeletionEvent.create(event, AmberUtils.content) } Client.send(event) LocalCache.consume(event) } - return null } fun createHTTPAuthorization(url: String, method: String, body: String? = null): HTTPAuthorizationEvent? { - if (!isWriteable()) return null + if (!isWriteable() && !loginWithAmber) return null - return HTTPAuthorizationEvent.create(url, method, body, keyPair.privKey!!) + var event = HTTPAuthorizationEvent.create(url, method, body, keyPair) + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return null + } + event = HTTPAuthorizationEvent.create(event, AmberUtils.content) + } + return event } - fun boost(note: Note, signEvent: Boolean): Event? { - if (!isWriteable() && signEvent) return null + fun boost(note: Note) { + if (!isWriteable() && !loginWithAmber) return if (note.hasBoostedInTheLast5Minutes(userProfile())) { // has already bosted in the past 5mins - return null + return } note.event?.let { if (it.kind() == 1) { - if (!signEvent) { - return RepostEvent.create(it, keyPair.pubKey.toHexKey()) + var event = RepostEvent.create(it, keyPair) + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = RepostEvent.create(event, AmberUtils.content) } - - val event = RepostEvent.create(it, keyPair.privKey!!) Client.send(event) LocalCache.consume(event) - return null } else { - if (!signEvent) { - return GenericRepostEvent.create(it, keyPair.pubKey.toHexKey()) + var event = GenericRepostEvent.create(it, keyPair) + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = GenericRepostEvent.create(event, AmberUtils.content) } - val event = GenericRepostEvent.create(it, keyPair.privKey!!) Client.send(event) LocalCache.consume(event) - return null } } - return null } fun broadcast(note: Note) { @@ -616,7 +648,25 @@ class Account( if (followingCommunities.isNotEmpty()) { followingCommunities.forEach { ATag.parse(it, null)?.let { - returningContactList = ContactListEvent.followAddressableEvent(returningContactList, it, keyPair) + if (loginWithAmber) { + val unsignedEvent = ContactListEvent.followAddressableEvent( + returningContactList, + it, + keyPair + ) + AmberUtils.openAmber(unsignedEvent) + returningContactList = if (AmberUtils.content.isBlank()) { + latestContactList + } else { + ContactListEvent.create(unsignedEvent, AmberUtils.content) + } + } else { + returningContactList = ContactListEvent.followAddressableEvent( + returningContactList, + it, + keyPair + ) + } } } followingCommunities = emptySet() @@ -632,12 +682,12 @@ class Account( return returningContactList } - fun follow(user: User, signEvent: Boolean): ContactListEvent? { - if (!isWriteable() && signEvent) return null + fun follow(user: User) { + if (!isWriteable() && !loginWithAmber) return val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) - val event = if (contactList != null) { + var event = if (contactList != null) { ContactListEvent.followUser(contactList, user.pubkeyHex, keyPair) } else { ContactListEvent.createFromScratch( @@ -651,21 +701,24 @@ class Account( ) } - if (!signEvent) { - return event + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = ContactListEvent.create(event, AmberUtils.content) } Client.send(event) LocalCache.consume(event) - return null } - fun follow(channel: Channel, signEvent: Boolean): ContactListEvent? { - if (!isWriteable() && signEvent) return null + fun follow(channel: Channel) { + if (!isWriteable() && !loginWithAmber) return val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) - val event = if (contactList != null) { + var event = if (contactList != null) { ContactListEvent.followEvent(contactList, channel.idHex, keyPair) } else { ContactListEvent.createFromScratch( @@ -679,21 +732,24 @@ class Account( ) } - if (!signEvent) { - return event + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = ContactListEvent.create(event, AmberUtils.content) } Client.send(event) LocalCache.consume(event) - return null } - fun follow(community: AddressableNote, signEvent: Boolean): ContactListEvent? { - if (!isWriteable() && signEvent) return null + fun follow(community: AddressableNote) { + if (!isWriteable() && !loginWithAmber) return val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) - val event = if (contactList != null) { + var event = if (contactList != null) { ContactListEvent.followAddressableEvent(contactList, community.address, keyPair) } else { val relays = Constants.defaultRelays.associate { it.url to ContactListEvent.ReadWrite(it.read, it.write) } @@ -708,21 +764,24 @@ class Account( ) } - if (!signEvent) { - return event + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = ContactListEvent.create(event, AmberUtils.content) } Client.send(event) LocalCache.consume(event) - return null } - fun followHashtag(tag: String, signEvent: Boolean): ContactListEvent? { - if (!isWriteable() && signEvent) return null + fun followHashtag(tag: String) { + if (!isWriteable() && !loginWithAmber) return val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) - val event = if (contactList != null) { + var event = if (contactList != null) { ContactListEvent.followHashtag( contactList, tag, @@ -740,21 +799,24 @@ class Account( ) } - if (!signEvent) { - return event + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = ContactListEvent.create(event, AmberUtils.content) } Client.send(event) LocalCache.consume(event) - return null } - fun followGeohash(geohash: String, signEvent: Boolean): ContactListEvent? { - if (!isWriteable() && signEvent) return null + fun followGeohash(geohash: String) { + if (!isWriteable() && !loginWithAmber) return val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) - val event = if (contactList != null) { + var event = if (contactList != null) { ContactListEvent.followGeohash( contactList, geohash, @@ -772,128 +834,141 @@ class Account( ) } - if (!signEvent) { - return event + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = ContactListEvent.create(event, AmberUtils.content) } Client.send(event) LocalCache.consume(event) - return null } - fun unfollow(user: User, signEvent: Boolean): ContactListEvent? { - if (!isWriteable() && signEvent) return null + fun unfollow(user: User) { + if (!isWriteable() && !loginWithAmber) return val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) if (contactList != null && contactList.tags.isNotEmpty()) { - val event = ContactListEvent.unfollowUser( + var event = ContactListEvent.unfollowUser( contactList, user.pubkeyHex, keyPair ) - if (!signEvent) { - return event + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = ContactListEvent.create(event, AmberUtils.content) } Client.send(event) LocalCache.consume(event) } - - return null } - fun unfollowHashtag(tag: String, signEvent: Boolean): ContactListEvent? { - if (!isWriteable() && signEvent) return null + fun unfollowHashtag(tag: String) { + if (!isWriteable() && !loginWithAmber) return val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) if (contactList != null && contactList.tags.isNotEmpty()) { - val event = ContactListEvent.unfollowHashtag( + var event = ContactListEvent.unfollowHashtag( contactList, tag, keyPair ) - if (!signEvent) { - return event + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = ContactListEvent.create(event, AmberUtils.content) } Client.send(event) LocalCache.consume(event) - - return null } - - return null } - fun unfollowGeohash(geohash: String, signEvent: Boolean): ContactListEvent? { - if (!isWriteable() && signEvent) return null + fun unfollowGeohash(geohash: String) { + if (!isWriteable() && !loginWithAmber) return val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) if (contactList != null && contactList.tags.isNotEmpty()) { - val event = ContactListEvent.unfollowGeohash( + var event = ContactListEvent.unfollowGeohash( contactList, geohash, keyPair ) - if (!signEvent) { - return event + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = ContactListEvent.create(event, AmberUtils.content) } Client.send(event) LocalCache.consume(event) - return null } - return null } - fun unfollow(channel: Channel, signEvent: Boolean): ContactListEvent? { - if (!isWriteable() && signEvent) return null + fun unfollow(channel: Channel) { + if (!isWriteable() && !loginWithAmber) return val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) if (contactList != null && contactList.tags.isNotEmpty()) { - val event = ContactListEvent.unfollowEvent( + var event = ContactListEvent.unfollowEvent( contactList, channel.idHex, keyPair ) - if (!signEvent) { - return event + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = ContactListEvent.create(event, AmberUtils.content) } Client.send(event) LocalCache.consume(event) } - return null } - fun unfollow(community: AddressableNote, signEvent: Boolean): ContactListEvent? { - if (!isWriteable() && signEvent) return null + fun unfollow(community: AddressableNote) { + if (!isWriteable() && !loginWithAmber) return val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) if (contactList != null && contactList.tags.isNotEmpty()) { - val event = ContactListEvent.unfollowAddressableEvent( + var event = ContactListEvent.unfollowAddressableEvent( contactList, community.address, keyPair ) - if (!signEvent) { - return event + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = ContactListEvent.create(event, AmberUtils.content) } Client.send(event) LocalCache.consume(event) } - return null } fun createNip95(byteArray: ByteArray, headerInfo: FileHeader): Pair? { @@ -1039,16 +1114,15 @@ class Account( root: String?, directMentions: Set, relayList: List? = null, - geohash: String? = null, - signEvent: Boolean - ): TextNoteEvent? { - if (!isWriteable() && signEvent) return null + geohash: String? = null + ) { + if (!isWriteable() && !loginWithAmber) return val repliesToHex = replyTo?.filter { it.address() == null }?.map { it.idHex } val mentionsHex = mentions?.map { it.pubkeyHex } val addresses = replyTo?.mapNotNull { it.address() } - val signedEvent = TextNoteEvent.create( + var signedEvent = TextNoteEvent.create( msg = message, replyTos = repliesToHex, mentions = mentionsHex, @@ -1064,8 +1138,12 @@ class Account( keyPair = keyPair ) - if (!signEvent) { - return signedEvent + if (loginWithAmber) { + AmberUtils.openAmber(signedEvent) + if (AmberUtils.content.isBlank()) { + return + } + signedEvent = TextNoteEvent.create(signedEvent, AmberUtils.content) } Client.send(signedEvent, relayList = relayList) @@ -1087,7 +1165,6 @@ class Account( Client.send(it, relayList = relayList) } } - return null } fun sendPoll( @@ -1103,16 +1180,15 @@ class Account( wantsToMarkAsSensitive: Boolean, zapRaiserAmount: Long? = null, relayList: List? = null, - geohash: String? = null, - signEvent: Boolean - ): PollNoteEvent? { - if (!isWriteable() && signEvent) return null + geohash: String? = null + ) { + if (!isWriteable() && !loginWithAmber) return val repliesToHex = replyTo?.map { it.idHex } val mentionsHex = mentions?.map { it.pubkeyHex } val addresses = replyTo?.mapNotNull { it.address() } - val signedEvent = PollNoteEvent.create( + var signedEvent = PollNoteEvent.create( msg = message, replyTos = repliesToHex, mentions = mentionsHex, @@ -1131,8 +1207,12 @@ class Account( ) // println("Sending new PollNoteEvent: %s".format(signedEvent.toJson())) - if (!signEvent) { - return signedEvent + if (loginWithAmber) { + AmberUtils.openAmber(signedEvent) + if (AmberUtils.content.isBlank()) { + return + } + signedEvent = PollNoteEvent.create(signedEvent, AmberUtils.content) } Client.send(signedEvent, relayList = relayList) @@ -1148,7 +1228,6 @@ class Account( Client.send(it, relayList = relayList) } } - return null } fun sendChannelMessage( @@ -1159,16 +1238,15 @@ class Account( zapReceiver: String? = null, wantsToMarkAsSensitive: Boolean, zapRaiserAmount: Long? = null, - geohash: String? = null, - signEvent: Boolean - ): ChannelMessageEvent? { - if (!isWriteable() && signEvent) return null + geohash: String? = null + ) { + if (!isWriteable() && !loginWithAmber) return // val repliesToHex = listOfNotNull(replyingTo?.idHex).ifEmpty { null } val repliesToHex = replyTo?.map { it.idHex } val mentionsHex = mentions?.map { it.pubkeyHex } - val signedEvent = ChannelMessageEvent.create( + var signedEvent = ChannelMessageEvent.create( message = message, channel = toChannel, replyTos = repliesToHex, @@ -1177,17 +1255,19 @@ class Account( markAsSensitive = wantsToMarkAsSensitive, zapRaiserAmount = zapRaiserAmount, geohash = geohash, - pubKey = keyPair.pubKey.toHexKey(), - privateKey = keyPair.privKey + keyPair = keyPair ) - if (!signEvent) { - return signedEvent + if (loginWithAmber) { + AmberUtils.openAmber(signedEvent) + if (AmberUtils.content.isBlank()) { + return + } + signedEvent = ChannelMessageEvent.create(signedEvent, AmberUtils.content) } Client.send(signedEvent) LocalCache.consume(signedEvent, null) - return null } fun sendLiveMessage( @@ -1198,16 +1278,15 @@ class Account( zapReceiver: String? = null, wantsToMarkAsSensitive: Boolean, zapRaiserAmount: Long? = null, - geohash: String? = null, - signEvent: Boolean - ): LiveActivitiesChatMessageEvent? { - if (!isWriteable() && signEvent) return null + geohash: String? = null + ) { + if (!isWriteable() && !loginWithAmber) return // val repliesToHex = listOfNotNull(replyingTo?.idHex).ifEmpty { null } val repliesToHex = replyTo?.map { it.idHex } val mentionsHex = mentions?.map { it.pubkeyHex } - val signedEvent = LiveActivitiesChatMessageEvent.create( + var signedEvent = LiveActivitiesChatMessageEvent.create( message = message, activity = toChannel, replyTos = repliesToHex, @@ -1216,21 +1295,23 @@ class Account( markAsSensitive = wantsToMarkAsSensitive, zapRaiserAmount = zapRaiserAmount, geohash = geohash, - pubKey = keyPair.pubKey.toHexKey(), - privateKey = keyPair.privKey + keyPair = keyPair ) - if (!signEvent) { - return signedEvent + if (loginWithAmber) { + AmberUtils.openAmber(signedEvent) + if (AmberUtils.content.isBlank()) { + return + } + signedEvent = LiveActivitiesChatMessageEvent.create(signedEvent, AmberUtils.content) } Client.send(signedEvent) LocalCache.consume(signedEvent, null) - return null } - fun sendPrivateMessage(message: String, toUser: User, replyingTo: Note? = null, mentions: List?, zapReceiver: String? = null, wantsToMarkAsSensitive: Boolean, zapRaiserAmount: Long? = null, geohash: String? = null): PrivateDmEvent? { - return sendPrivateMessage(message, toUser.pubkeyHex, replyingTo, mentions, zapReceiver, wantsToMarkAsSensitive, zapRaiserAmount, geohash, true) + fun sendPrivateMessage(message: String, toUser: User, replyingTo: Note? = null, mentions: List?, zapReceiver: String? = null, wantsToMarkAsSensitive: Boolean, zapRaiserAmount: Long? = null, geohash: String? = null) { + sendPrivateMessage(message, toUser.pubkeyHex, replyingTo, mentions, zapReceiver, wantsToMarkAsSensitive, zapRaiserAmount, geohash) } fun sendPrivateMessage( @@ -1241,36 +1322,45 @@ class Account( zapReceiver: String? = null, wantsToMarkAsSensitive: Boolean, zapRaiserAmount: Long? = null, - geohash: String? = null, - signEvent: Boolean - ): PrivateDmEvent? { - if (!isWriteable() && signEvent) return null + geohash: String? = null + ) { + if (!isWriteable() && !loginWithAmber) return val repliesToHex = listOfNotNull(replyingTo?.idHex).ifEmpty { null } val mentionsHex = mentions?.map { it.pubkeyHex } - val signedEvent = PrivateDmEvent.create( + var localMessage = message + if (loginWithAmber) { + AmberUtils.content = "" + AmberUtils.encrypt(localMessage, toUser) + if (AmberUtils.content.isBlank()) return + localMessage = AmberUtils.content + } + + var signedEvent = PrivateDmEvent.create( recipientPubKey = toUser.hexToByteArray(), publishedRecipientPubKey = toUser.hexToByteArray(), - msg = message, + msg = localMessage, replyTos = repliesToHex, mentions = mentionsHex, zapReceiver = zapReceiver, markAsSensitive = wantsToMarkAsSensitive, zapRaiserAmount = zapRaiserAmount, geohash = geohash, - pubKey = keyPair.pubKey.toHexKey(), - privateKey = keyPair.privKey, + keyPair = keyPair, advertiseNip18 = false ) - if (!signEvent) { - return signedEvent + if (loginWithAmber) { + AmberUtils.openAmber(signedEvent) + if (AmberUtils.content.isBlank()) { + return + } + signedEvent = PrivateDmEvent.create(signedEvent, AmberUtils.content) } Client.send(signedEvent) LocalCache.consume(signedEvent, null) - return null } fun sendNIP24PrivateMessage( @@ -1282,10 +1372,10 @@ class Account( zapReceiver: String? = null, wantsToMarkAsSensitive: Boolean, zapRaiserAmount: Long? = null, - geohash: String? = null, - signEvent: Boolean + geohash: String? = null ): List? { - if (!isWriteable() && signEvent) return null + // TODO: add support for amber + if (!isWriteable() && !loginWithAmber) return null val repliesToHex = listOfNotNull(replyingTo?.idHex).ifEmpty { null } val mentionsHex = mentions?.map { it.pubkeyHex } @@ -1303,7 +1393,7 @@ class Account( from = keyPair.privKey!! ) - if (!signEvent) { + if (loginWithAmber) { return signedEvents } @@ -1333,7 +1423,7 @@ class Account( } fun sendCreateNewChannel(name: String, about: String, picture: String) { - if (!isWriteable()) return + if (!isWriteable() && !loginWithAmber) return val metadata = ChannelCreateEvent.ChannelData( name, @@ -1341,16 +1431,24 @@ class Account( picture ) - val event = ChannelCreateEvent.create( + var event = ChannelCreateEvent.create( channelInfo = metadata, - privateKey = keyPair.privKey!! + keyPair = keyPair ) + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = ChannelCreateEvent.create(event, AmberUtils.content) + } + Client.send(event) LocalCache.consume(event) LocalCache.getChannelIfExists(event.id)?.let { - follow(it, true) + follow(it) } } @@ -1433,7 +1531,7 @@ class Account( LocalCache.consume(event) } - fun addPrivateBookmark(note: Note, decryptedContent: String): BookmarkListEvent? { + fun addPrivateBookmark(note: Note, decryptedContent: String) { val bookmarks = userProfile().latestBookmarkList val privTags = mutableListOf>() @@ -1463,10 +1561,10 @@ class Account( AmberUtils.encrypt(msg, keyPair.pubKey.toHexKey()) if (AmberUtils.content.isBlank()) { - return null + return } - return BookmarkListEvent.create( + var event = BookmarkListEvent.create( "bookmark", bookmarks?.taggedEvents() ?: emptyList(), bookmarks?.taggedUsers() ?: emptyList(), @@ -1476,9 +1574,18 @@ class Account( keyPair.pubKey.toHexKey() ) + + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = BookmarkListEvent.create(event, AmberUtils.content) + + Client.send(event) + LocalCache.consume(event) } - fun removePrivateBookmark(note: Note, decryptedContent: String): BookmarkListEvent? { + fun removePrivateBookmark(note: Note, decryptedContent: String) { val bookmarks = userProfile().latestBookmarkList val privTags = mutableListOf>() @@ -1508,10 +1615,10 @@ class Account( AmberUtils.encrypt(msg, keyPair.pubKey.toHexKey()) if (AmberUtils.content.isBlank()) { - return null + return } - return BookmarkListEvent.create( + var event = BookmarkListEvent.create( "bookmark", bookmarks?.taggedEvents() ?: emptyList(), bookmarks?.taggedUsers() ?: emptyList(), @@ -1521,6 +1628,15 @@ class Account( keyPair.pubKey.toHexKey() ) + + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = BookmarkListEvent.create(event, AmberUtils.content) + + Client.send(event) + LocalCache.consume(event) } fun addPrivateBookmark(note: Note) { @@ -1560,7 +1676,7 @@ class Account( LocalCache.consume(event) } - fun addPublicBookmark(note: Note, decryptedContent: String): BookmarkListEvent? { + fun addPublicBookmark(note: Note, decryptedContent: String) { val bookmarks = userProfile().latestBookmarkList val privTags = mutableListOf>() @@ -1583,10 +1699,10 @@ class Account( AmberUtils.encrypt(msg, keyPair.pubKey.toHexKey()) if (AmberUtils.content.isBlank()) { - return null + return } - val event = if (note is AddressableNote) { + var event = if (note is AddressableNote) { BookmarkListEvent.create( "bookmark", bookmarks?.taggedEvents() ?: emptyList(), @@ -1605,7 +1721,14 @@ class Account( keyPair.pubKey.toHexKey() ) } - return event + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = BookmarkListEvent.create(event, AmberUtils.content) + + Client.send(event) + LocalCache.consume(event) } fun addPublicBookmark(note: Note) { @@ -1682,10 +1805,19 @@ class Account( LocalCache.consume(event) } - fun createAuthEvent(relay: Relay, challenge: String, loggedInWithAmber: Boolean): RelayAuthEvent? { - if (!isWriteable() && !loggedInWithAmber) return null + fun createAuthEvent(relay: Relay, challenge: String): RelayAuthEvent? { + if (!isWriteable() && !loginWithAmber) return null - return RelayAuthEvent.create(relay.url, challenge, keyPair.pubKey.toHexKey(), keyPair.privKey) + var event = RelayAuthEvent.create(relay.url, challenge, keyPair.pubKey.toHexKey(), keyPair.privKey) + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return null + } + event = RelayAuthEvent.create(event, AmberUtils.content) + } + + return event } fun removePublicBookmark(note: Note) { @@ -1725,7 +1857,7 @@ class Account( LocalCache.consume(event) } - fun removePublicBookmark(note: Note, decryptedContent: String): BookmarkListEvent? { + fun removePublicBookmark(note: Note, decryptedContent: String) { val bookmarks = userProfile().latestBookmarkList val privTags = mutableListOf>() @@ -1748,10 +1880,10 @@ class Account( AmberUtils.encrypt(msg, keyPair.pubKey.toHexKey()) if (AmberUtils.content.isBlank()) { - return null + return } - val event = if (note is AddressableNote) { + var event = if (note is AddressableNote) { BookmarkListEvent.create( "bookmark", bookmarks?.taggedEvents() ?: emptyList(), @@ -1771,7 +1903,14 @@ class Account( ) } - return event + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) { + return + } + event = BookmarkListEvent.create(event, AmberUtils.content) + + Client.send(event) + LocalCache.consume(event) } fun isInPrivateBookmarks(note: Note): Boolean { @@ -1833,28 +1972,6 @@ class Account( return returningList } - fun hideUser(pubkeyHex: String, encryptedContent: String): PeopleListEvent { - val blockList = migrateHiddenUsersIfNeeded(getBlockList()) - - return if (blockList != null) { - PeopleListEvent.addUser( - earlierVersion = blockList, - pubKeyHex = pubkeyHex, - isPrivate = true, - pubKey = keyPair.pubKey.toHexKey(), - encryptedContent = encryptedContent - ) - } else { - PeopleListEvent.createListWithUser( - name = PeopleListEvent.blockList, - pubKeyHex = pubkeyHex, - isPrivate = true, - pubKey = keyPair.pubKey.toHexKey(), - encryptedContent = encryptedContent - ) - } - } - fun hideUser(pubkeyHex: String) { val blockList = migrateHiddenUsersIfNeeded(getBlockList()) if (loginWithAmber) { @@ -1937,33 +2054,59 @@ class Account( saveable.invalidateData() } - fun showUser(pubkeyHex: String, encryptedContent: String): PeopleListEvent? { - val blockList = migrateHiddenUsersIfNeeded(getBlockList()) - if (blockList != null) { - return PeopleListEvent.removeUser( - earlierVersion = blockList, - pubKeyHex = pubkeyHex, - isPrivate = true, - pubKey = keyPair.pubKey.toHexKey(), - encryptedContent = encryptedContent - ) - } - return null - } - fun showUser(pubkeyHex: String) { val blockList = migrateHiddenUsersIfNeeded(getBlockList()) if (blockList != null) { - val event = PeopleListEvent.removeUser( - earlierVersion = blockList, - pubKeyHex = pubkeyHex, - isPrivate = true, - privateKey = keyPair.privKey!! - ) + if (loginWithAmber) { + val content = blockList.content ?: "" + val encryptedContent = if (content.isBlank()) { + val privateTags = listOf(listOf("p", pubkeyHex)) + val msg = Event.mapper.writeValueAsString(privateTags) - Client.send(event) - LocalCache.consume(event) + AmberUtils.content = "" + AmberUtils.encrypt(msg, keyPair.pubKey.toHexKey()) + if (AmberUtils.content.isBlank()) return + AmberUtils.content + } else { + AmberUtils.content = "" + AmberUtils.decrypt(content, keyPair.pubKey.toHexKey()) + if (AmberUtils.content.isBlank()) return + val decryptedContent = AmberUtils.content + AmberUtils.content = "" + val privateTags = blockList.privateTagsOrEmpty(decryptedContent).minus(element = listOf("p", pubkeyHex)) + val msg = Event.mapper.writeValueAsString(privateTags) + AmberUtils.content = "" + AmberUtils.encrypt(msg, keyPair.pubKey.toHexKey()) + if (AmberUtils.content.isBlank()) return + AmberUtils.content + } + + var event = PeopleListEvent.addUser( + earlierVersion = blockList, + pubKeyHex = pubkeyHex, + isPrivate = true, + pubKey = keyPair.pubKey.toHexKey(), + encryptedContent + ) + + AmberUtils.content = "" + AmberUtils.openAmber(event) + event = PeopleListEvent.create(event, AmberUtils.content) + + Client.send(event) + LocalCache.consume(event) + } else { + val event = PeopleListEvent.removeUser( + earlierVersion = blockList, + pubKeyHex = pubkeyHex, + isPrivate = true, + privateKey = keyPair.privKey!! + ) + + Client.send(event) + LocalCache.consume(event) + } } transientHiddenUsers = (transientHiddenUsers - pubkeyHex).toImmutableSet() @@ -2147,7 +2290,7 @@ class Account( } fun sendChangeChannel(name: String, about: String, picture: String, channel: Channel) { - if (!isWriteable()) return + if (!isWriteable() && !loginWithAmber) return val metadata = ChannelCreateEvent.ChannelData( name, @@ -2155,16 +2298,21 @@ class Account( picture ) - val event = ChannelMetadataEvent.create( + var event = ChannelMetadataEvent.create( newChannelInfo = metadata, originalChannelIdHex = channel.idHex, - privateKey = keyPair.privKey!! + keyPair = keyPair ) + if (loginWithAmber) { + AmberUtils.openAmber(event) + if (AmberUtils.content.isBlank()) return + event = ChannelMetadataEvent.create(event, AmberUtils.content) + } Client.send(event) LocalCache.consume(event) - follow(channel, true) + follow(channel) } fun unwrap(event: GiftWrapEvent): Event? { @@ -2405,10 +2553,10 @@ class Account( ).toSet() } - fun saveRelayList(value: List, signEvent: Boolean): ContactListEvent? { + fun saveRelayList(value: List) { try { localRelays = value.toSet() - return sendNewRelayList(value.associate { it.url to ContactListEvent.ReadWrite(it.read, it.write) }, signEvent) + return sendNewRelayList(value.associate { it.url to ContactListEvent.ReadWrite(it.read, it.write) }) } finally { saveable.invalidateData() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/AmberUtils.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/AmberUtils.kt index 0f2e45920..3bbf32915 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/AmberUtils.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/AmberUtils.kt @@ -35,11 +35,29 @@ object AmberUtils { } fun openAmber(event: EventInterface) { + checkNotInMainThread() + ServiceManager.shouldPauseService = false + content = "" isActivityRunning = true openAmber( event.toJson(), SignerType.SIGN_EVENT, - IntentUtils.decryptActivityResultLauncher, + IntentUtils.activityResultLauncher, + "" + ) + while (isActivityRunning) { + // do nothing + } + } + + fun loginWithAmber() { + checkNotInMainThread() + content = "" + isActivityRunning = true + openAmber( + "", + SignerType.GET_PUBLIC_KEY, + IntentUtils.activityResultLauncher, "" ) while (isActivityRunning) { @@ -53,7 +71,7 @@ object AmberUtils { openAmber( encryptedContent, SignerType.NIP04_DECRYPT, - IntentUtils.decryptActivityResultLauncher, + IntentUtils.activityResultLauncher, pubKey ) while (isActivityRunning) { @@ -68,7 +86,7 @@ object AmberUtils { openAmber( decryptedContent, SignerType.NIP04_ENCRYPT, - IntentUtils.decryptActivityResultLauncher, + IntentUtils.activityResultLauncher, pubKey ) while (isActivityRunning) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/IntentUtils.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/IntentUtils.kt index 4a282fe9e..3a9e5c227 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/IntentUtils.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/IntentUtils.kt @@ -6,14 +6,8 @@ import android.widget.Toast import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import com.vitorpamplona.amethyst.Amethyst -import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.ServiceManager -import com.vitorpamplona.amethyst.service.notifications.PushNotificationUtils -import com.vitorpamplona.amethyst.service.notifications.RegisterAccounts -import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.ui.MainActivity -import com.vitorpamplona.quartz.events.Event -import com.vitorpamplona.quartz.events.RelayAuthEvent import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope @@ -21,64 +15,11 @@ import kotlinx.coroutines.launch object IntentUtils { lateinit var activityResultLauncher: ActivityResultLauncher - lateinit var authActivityResultLauncher: ActivityResultLauncher - lateinit var decryptActivityResultLauncher: ActivityResultLauncher @OptIn(DelicateCoroutinesApi::class) fun start(activity: MainActivity) { activityResultLauncher = activity.registerForActivityResult( ActivityResultContracts.StartActivityForResult() - ) { - if (it.resultCode != Activity.RESULT_OK) { - GlobalScope.launch(Dispatchers.Main) { - Toast.makeText( - Amethyst.instance, - "Sign request rejected", - Toast.LENGTH_SHORT - ).show() - } - return@registerForActivityResult - } - - val event = it.data?.getStringExtra("event") ?: "" - - val signedEvent = Event.fromJson(event) - val authEvent = RelayAuthEvent(signedEvent.id, signedEvent.pubKey, signedEvent.createdAt, signedEvent.tags, signedEvent.content, signedEvent.sig) - - RegisterAccounts(LocalPreferences.allSavedAccounts()).postRegistrationEvent( - listOf(authEvent) - ) - PushNotificationUtils.hasInit = true - ServiceManager.shouldPauseService = true - } - - authActivityResultLauncher = activity.registerForActivityResult( - ActivityResultContracts.StartActivityForResult() - ) { - if (it.resultCode != Activity.RESULT_OK) { - GlobalScope.launch(Dispatchers.Main) { - Toast.makeText( - Amethyst.instance, - "Sign request rejected", - Toast.LENGTH_SHORT - ).show() - } - return@registerForActivityResult - } - - val event = it.data?.getStringExtra("event") ?: "" - - val signedEvent = Event.fromJson(event) - val authEvent = RelayAuthEvent(signedEvent.id, signedEvent.pubKey, signedEvent.createdAt, signedEvent.tags, signedEvent.content, signedEvent.sig) - - GlobalScope.launch(Dispatchers.IO) { - Client.send(authEvent, authEvent.relay()) - } - ServiceManager.shouldPauseService = true - } - - decryptActivityResultLauncher = activity.registerForActivityResult( - ActivityResultContracts.StartActivityForResult() ) { if (it.resultCode != Activity.RESULT_OK) { GlobalScope.launch(Dispatchers.Main) { @@ -95,6 +36,7 @@ object IntentUtils { val event = it.data?.getStringExtra("signature") ?: "" AmberUtils.content = event AmberUtils.isActivityRunning = false + ServiceManager.shouldPauseService = true } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt index c1edd934d..a7dadcb49 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt @@ -8,7 +8,6 @@ import com.vitorpamplona.amethyst.service.relays.EOSEAccount import com.vitorpamplona.amethyst.service.relays.JsonFilter import com.vitorpamplona.amethyst.service.relays.Relay import com.vitorpamplona.amethyst.service.relays.TypedFilter -import com.vitorpamplona.amethyst.ui.actions.SignerType import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent import com.vitorpamplona.quartz.events.BadgeAwardEvent import com.vitorpamplona.quartz.events.BadgeProfilesEvent @@ -190,25 +189,13 @@ object NostrAccountDataSource : NostrDataSource("AccountData") { super.auth(relay, challenge) if (this::account.isInitialized) { - val loggedInWithAmber = account.loginWithAmber - val event = account.createAuthEvent(relay, challenge, loggedInWithAmber) + val event = account.createAuthEvent(relay, challenge) - if (loggedInWithAmber && !account.isWriteable()) { - if (event != null) { - AmberUtils.openAmber( - event.toJson(), - SignerType.SIGN_EVENT, - IntentUtils.authActivityResultLauncher, - "" - ) - } - } else { - if (event != null) { - Client.send( - event, - relay.url - ) - } + if (event != null) { + Client.send( + event, + relay.url + ) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt index e348da44f..58fd00425 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt @@ -4,10 +4,7 @@ import android.util.Log import com.vitorpamplona.amethyst.AccountInfo import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.LocalPreferences -import com.vitorpamplona.amethyst.service.AmberUtils import com.vitorpamplona.amethyst.service.HttpClient -import com.vitorpamplona.amethyst.service.IntentUtils -import com.vitorpamplona.amethyst.ui.actions.SignerType import com.vitorpamplona.quartz.events.RelayAuthEvent import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -22,16 +19,14 @@ class RegisterAccounts( // creates proof that it controls all accounts private fun signEventsToProveControlOfAccounts( accounts: List, - notificationToken: String, - loggedInWithAmber: Boolean + notificationToken: String ): List { return accounts.mapNotNull { val acc = LocalPreferences.loadFromEncryptedStorage(it.npub) if (acc != null) { val relayToUse = acc.activeRelays()?.firstOrNull { it.read } if (relayToUse != null) { - val event = acc.createAuthEvent(relayToUse, notificationToken, loggedInWithAmber) - event + acc.createAuthEvent(relayToUse, notificationToken) } else { null } @@ -68,25 +63,8 @@ class RegisterAccounts( } suspend fun go(notificationToken: String) = withContext(Dispatchers.IO) { - val accountsWithoutPrivKey = accounts.filter { !it.hasPrivKey } - val accountsWithPrivKey = accounts.filter { it.hasPrivKey } - accountsWithoutPrivKey.forEach { account -> - Log.d("fcm register", account.npub) - val events = signEventsToProveControlOfAccounts(listOf(account), notificationToken, account.loggedInWithAmber) - if (events.isNotEmpty()) { - AmberUtils.openAmber( - events.first().toJson(), - SignerType.SIGN_EVENT, - IntentUtils.activityResultLauncher, - "" - ) - } - } - - if (accountsWithPrivKey.isNotEmpty()) { - postRegistrationEvent( - signEventsToProveControlOfAccounts(accountsWithPrivKey, notificationToken, false) - ) - } + postRegistrationEvent( + signEventsToProveControlOfAccounts(accounts, notificationToken) + ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt index 2905649a0..fc43a4293 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt @@ -75,14 +75,12 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberPermissionState import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.ServersAvailable import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.NostrSearchEventOrUserDataSource import com.vitorpamplona.amethyst.service.ReverseGeoLocationUtil import com.vitorpamplona.amethyst.service.noProtocolUrlValidator -import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.ui.components.* import com.vitorpamplona.amethyst.ui.note.CancelIcon import com.vitorpamplona.amethyst.ui.note.CloseIcon @@ -105,7 +103,6 @@ import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.replyModifier import com.vitorpamplona.amethyst.ui.theme.subtleBorder -import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.toImmutableListOfLists import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList @@ -162,25 +159,6 @@ fun NewPostView( } } - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent, relayList = relayList) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - onClose() - } - }, - data = event!!.toJson() - ) - } - Dialog( onDismissRequest = { onClose() }, properties = DialogProperties( @@ -234,10 +212,8 @@ fun NewPostView( PostButton( onPost = { scope.launch(Dispatchers.IO) { - event = postViewModel.sendPost(relayList = relayList, !accountViewModel.loggedInWithAmber()) - if (!accountViewModel.loggedInWithAmber()) { - onClose() - } + postViewModel.sendPost(relayList = relayList) + onClose() } }, isActive = postViewModel.canPost() 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 b6c5b7a26..e1b291223 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 @@ -14,7 +14,11 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.fonfon.kgeohash.toGeoHash -import com.vitorpamplona.amethyst.model.* +import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.model.LocalCache +import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.model.ServersAvailable +import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.FileHeader import com.vitorpamplona.amethyst.service.LocationUtil import com.vitorpamplona.amethyst.service.NostrSearchEventOrUserDataSource @@ -27,7 +31,6 @@ import com.vitorpamplona.quartz.events.AddressableEvent import com.vitorpamplona.quartz.events.BaseTextNoteEvent import com.vitorpamplona.quartz.events.ChatMessageEvent import com.vitorpamplona.quartz.events.CommunityDefinitionEvent -import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.PrivateDmEvent import com.vitorpamplona.quartz.events.TextNoteEvent import kotlinx.coroutines.Dispatchers @@ -158,7 +161,7 @@ open class NewPostViewModel() : ViewModel() { this.account = account } - fun sendPost(relayList: List? = null, signEvent: Boolean): Event? { + fun sendPost(relayList: List? = null) { try { val tagger = NewMessageTagger(message.text, mentions, replyTos, originalNote?.channelHex()) tagger.run() @@ -188,13 +191,12 @@ open class NewPostViewModel() : ViewModel() { if (originalNote?.channelHex() != null) { if (originalNote is AddressableEvent && originalNote?.address() != null) { - return account?.sendLiveMessage(tagger.message, originalNote?.address()!!, tagger.replyTos, tagger.mentions, zapReceiver, wantsToMarkAsSensitive, localZapRaiserAmount, geoHash, signEvent) + account?.sendLiveMessage(tagger.message, originalNote?.address()!!, tagger.replyTos, tagger.mentions, zapReceiver, wantsToMarkAsSensitive, localZapRaiserAmount, geoHash) } else { - return account?.sendChannelMessage(tagger.message, tagger.channelHex!!, tagger.replyTos, tagger.mentions, zapReceiver, wantsToMarkAsSensitive, localZapRaiserAmount, geoHash, signEvent) + account?.sendChannelMessage(tagger.message, tagger.channelHex!!, tagger.replyTos, tagger.mentions, zapReceiver, wantsToMarkAsSensitive, localZapRaiserAmount, geoHash) } } else if (originalNote?.event is PrivateDmEvent) { account?.sendPrivateMessage(tagger.message, originalNote!!.author!!, originalNote!!, tagger.mentions, zapReceiver, wantsToMarkAsSensitive, localZapRaiserAmount, geoHash) - return null } else if (originalNote?.event is ChatMessageEvent) { val receivers = (originalNote?.event as ChatMessageEvent).recipientsPubKey().plus(originalNote?.author?.pubkeyHex).filterNotNull().toSet().toList() @@ -207,10 +209,8 @@ open class NewPostViewModel() : ViewModel() { wantsToMarkAsSensitive = wantsToMarkAsSensitive, zapReceiver = zapReceiver, zapRaiserAmount = localZapRaiserAmount, - geohash = geoHash, - signEvent = signEvent + geohash = geoHash ) - return null } else if (!dmUsers.isNullOrEmpty()) { if (nip24 || dmUsers.size > 1) { account?.sendNIP24PrivateMessage( @@ -222,10 +222,8 @@ open class NewPostViewModel() : ViewModel() { wantsToMarkAsSensitive = wantsToMarkAsSensitive, zapReceiver = zapReceiver, zapRaiserAmount = localZapRaiserAmount, - geohash = geoHash, - signEvent = signEvent + geohash = geoHash ) - return null } else { account?.sendPrivateMessage( message = tagger.message, @@ -235,14 +233,12 @@ open class NewPostViewModel() : ViewModel() { wantsToMarkAsSensitive = wantsToMarkAsSensitive, zapReceiver = zapReceiver, zapRaiserAmount = localZapRaiserAmount, - geohash = geoHash, - signEvent = signEvent + geohash = geoHash ) - return null } } else { if (wantsPoll) { - return account?.sendPoll( + account?.sendPoll( tagger.message, tagger.replyTos, tagger.mentions, @@ -255,8 +251,7 @@ open class NewPostViewModel() : ViewModel() { wantsToMarkAsSensitive, localZapRaiserAmount, relayList, - geoHash, - signEvent + geoHash ) } else { // adds markers @@ -266,7 +261,7 @@ open class NewPostViewModel() : ViewModel() { ?: originalNote?.replyTo?.firstOrNull()?.idHex // old rules, first item is root. val replyId = originalNote?.idHex - return account?.sendPost( + account?.sendPost( message = tagger.message, replyTo = tagger.replyTos, mentions = tagger.mentions, @@ -278,8 +273,7 @@ open class NewPostViewModel() : ViewModel() { root = rootId, directMentions = tagger.directMentions, relayList = relayList, - geohash = geoHash, - signEvent = signEvent + geohash = geoHash ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewRelayListView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewRelayListView.kt index 2a7bab0aa..3abfba9ef 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewRelayListView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewRelayListView.kt @@ -56,10 +56,8 @@ import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.RelayInformation import com.vitorpamplona.amethyst.model.RelaySetupInfo -import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.service.relays.Constants.defaultRelays import com.vitorpamplona.amethyst.service.relays.FeedType import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -69,9 +67,7 @@ import com.vitorpamplona.amethyst.ui.theme.Size35dp import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.placeholderText -import com.vitorpamplona.quartz.events.Event import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.lang.Math.round @@ -91,26 +87,6 @@ fun NewRelayListView(onClose: () -> Unit, accountViewModel: AccountViewModel, re } } - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - postViewModel.clear() - onClose() - } - }, - data = event!!.toJson() - ) - } - Dialog( onDismissRequest = onClose, properties = DialogProperties(usePlatformDefaultWidth = false) @@ -144,12 +120,8 @@ fun NewRelayListView(onClose: () -> Unit, accountViewModel: AccountViewModel, re PostButton( onPost = { - if (accountViewModel.loggedInWithAmber()) { - event = postViewModel.create(false) - } else { - postViewModel.create(true) - onClose() - } + postViewModel.create() + onClose() }, true ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewRelayListViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewRelayListViewModel.kt index 539844545..ef787703a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewRelayListViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewRelayListViewModel.kt @@ -26,20 +26,14 @@ class NewRelayListViewModel : ViewModel() { clear() } - fun create(signEvent: Boolean): ContactListEvent? { - if (!signEvent) { - relays.let { - return account.saveRelayList(it.value, false) - } - } + fun create() { relays.let { viewModelScope.launch(Dispatchers.IO) { - account.saveRelayList(it.value, true) + account.saveRelayList(it.value) } } clear() - return null } fun clear() { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataView.kt index e0c238873..18469e3ce 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataView.kt @@ -17,11 +17,7 @@ import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -33,10 +29,7 @@ import androidx.compose.ui.window.DialogProperties import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.LocalCache -import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.ui.theme.placeholderText -import com.vitorpamplona.quartz.events.Event import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -70,26 +63,6 @@ fun NewUserMetadataView(onClose: () -> Unit, account: Account) { Column( modifier = Modifier.padding(10.dp) ) { - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - postViewModel.clear() - onClose() - } - }, - data = event!!.toJson() - ) - } - Row( modifier = Modifier .fillMaxWidth(), @@ -103,12 +76,8 @@ fun NewUserMetadataView(onClose: () -> Unit, account: Account) { PostButton( onPost = { - if (account.loginWithAmber) { - event = postViewModel.create(false) - } else { - postViewModel.create(true) - onClose() - } + postViewModel.create() + onClose() }, true ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt index da28bb30e..f46482178 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt @@ -13,7 +13,6 @@ import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.ui.components.MediaCompressor import com.vitorpamplona.quartz.events.GitHubIdentity import com.vitorpamplona.quartz.events.MastodonIdentity -import com.vitorpamplona.quartz.events.MetadataEvent import com.vitorpamplona.quartz.events.TwitterIdentity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow @@ -73,7 +72,7 @@ class NewUserMetadataViewModel : ViewModel() { } } - fun create(signEvent: Boolean): MetadataEvent? { + fun create() { // Tries to not delete any existing attribute that we do not work with. val latest = account.userProfile().info?.latestMetadata val currentJson = if (latest != null) { @@ -122,16 +121,10 @@ class NewUserMetadataViewModel : ViewModel() { val writer = StringWriter() ObjectMapper().writeValue(writer, currentJson) - if (signEvent) { - viewModelScope.launch(Dispatchers.IO) { - account.sendNewUserMetadata(writer.buffer.toString(), newClaims, true) - } - clear() - } else { - return account.sendNewUserMetadata(writer.buffer.toString(), newClaims, false) + viewModelScope.launch(Dispatchers.IO) { + account.sendNewUserMetadata(writer.buffer.toString(), newClaims) } - - return null + clear() } fun clear() { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SignerDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SignerDialog.kt index 3708d59e8..3739352ab 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SignerDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SignerDialog.kt @@ -30,7 +30,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties @@ -41,8 +40,6 @@ import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.events.Event -import com.vitorpamplona.quartz.events.TextNoteEvent -import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.launch enum class SignerType { @@ -189,15 +186,3 @@ fun SignerDialog( } } } - -@Preview -@Composable -fun Test() { - SignerDialog( - onClose = { }, - onPost = { }, - data = TextNoteEvent("", "", TimeUtils.now(), emptyList(), "test", "").toJson(), - type = SignerType.SIGN_EVENT, - pubKey = "" - ) -} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/AddBountyAmountDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/AddBountyAmountDialog.kt index e12228955..19148d6dc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/AddBountyAmountDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/AddBountyAmountDialog.kt @@ -17,7 +17,6 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -33,16 +32,11 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note -import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.actions.PostButton -import com.vitorpamplona.amethyst.ui.actions.SignerDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.placeholderText -import com.vitorpamplona.quartz.events.Event -import com.vitorpamplona.quartz.events.TextNoteEvent import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -57,11 +51,11 @@ class AddBountyAmountViewModel : ViewModel() { this.bounty = bounty } - fun sendPost(signEvent: Boolean): TextNoteEvent? { + fun sendPost() { val newValue = nextAmount.text.trim().toLongOrNull() if (newValue != null) { - val event = account?.sendPost( + account?.sendPost( message = newValue.toString(), replyTo = listOfNotNull(bounty), mentions = listOfNotNull(bounty?.author), @@ -69,14 +63,11 @@ class AddBountyAmountViewModel : ViewModel() { wantsToMarkAsSensitive = false, replyingTo = null, root = null, - directMentions = setOf(), - signEvent = signEvent + directMentions = setOf() ) nextAmount = TextFieldValue("") - return event } - return null } fun cancel() { @@ -94,25 +85,6 @@ fun AddBountyAmountDialog(bounty: Note, accountViewModel: AccountViewModel, onCl postViewModel.load(accountViewModel.account, bounty) val scope = rememberCoroutineScope() - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - onClose() - } - }, - data = event!!.toJson() - ) - } - Dialog( onDismissRequest = { onClose() }, properties = DialogProperties( @@ -138,8 +110,8 @@ fun AddBountyAmountDialog(bounty: Note, accountViewModel: AccountViewModel, onCl PostButton( onPost = { - event = postViewModel.sendPost(!accountViewModel.loggedInWithAmber()) - if (!accountViewModel.loggedInWithAmber()) { + scope.launch(Dispatchers.IO) { + postViewModel.sendPost() onClose() } }, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt index 1b97c6e3d..4a8d53283 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt @@ -37,11 +37,9 @@ import androidx.compose.material.icons.filled.Report import androidx.compose.material.icons.filled.Share import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.shadow @@ -62,17 +60,13 @@ import androidx.core.content.ContextCompat import androidx.core.graphics.ColorUtils import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.AddressableNote -import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note -import com.vitorpamplona.amethyst.service.relays.Client -import com.vitorpamplona.amethyst.ui.actions.SignerDialog import com.vitorpamplona.amethyst.ui.components.SelectTextDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.ReportNoteDialog import com.vitorpamplona.amethyst.ui.theme.WarningColor import com.vitorpamplona.amethyst.ui.theme.secondaryButtonBackground import com.vitorpamplona.quartz.events.AudioTrackEvent -import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.FileHeaderEvent import com.vitorpamplona.quartz.events.PeopleListEvent import kotlinx.coroutines.Dispatchers @@ -206,25 +200,6 @@ private fun RenderMainPopup( val isOwnNote = accountViewModel.isLoggedUser(note.author) val isFollowingUser = !isOwnNote && accountViewModel.isFollowing(note.author) - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - onDismiss() - } - }, - data = event!!.toJson() - ) - } - Popup(onDismissRequest = onDismiss, alignment = Alignment.Center) { Card( modifier = Modifier.shadow(elevation = 6.dp, shape = cardShape), @@ -300,10 +275,8 @@ private fun RenderMainPopup( ) { if (accountViewModel.hideDeleteRequestDialog) { scope.launch(Dispatchers.IO) { - event = accountViewModel.delete(note, !accountViewModel.loggedInWithAmber()) - if (!accountViewModel.loggedInWithAmber()) { - onDismiss() - } + accountViewModel.delete(note) + onDismiss() } } else { showDeleteAlertDialog.value = true @@ -315,10 +288,8 @@ private fun RenderMainPopup( stringResource(R.string.quick_action_unfollow) ) { scope.launch(Dispatchers.IO) { - event = accountViewModel.unfollow(note.author!!, !accountViewModel.loggedInWithAmber()) - if (!accountViewModel.loggedInWithAmber()) { - onDismiss() - } + accountViewModel.unfollow(note.author!!) + onDismiss() } } } else { @@ -327,10 +298,8 @@ private fun RenderMainPopup( stringResource(R.string.quick_action_follow) ) { scope.launch(Dispatchers.IO) { - event = accountViewModel.follow(note.author!!, !accountViewModel.loggedInWithAmber()) - if (!accountViewModel.loggedInWithAmber()) { - onDismiss() - } + accountViewModel.follow(note.author!!) + onDismiss() } } } @@ -413,25 +382,6 @@ fun NoteQuickActionItem(icon: ImageVector, label: String, onClick: () -> Unit) { fun DeleteAlertDialog(note: Note, accountViewModel: AccountViewModel, onDismiss: () -> Unit) { val scope = rememberCoroutineScope() - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - onDismiss() - } - }, - data = event!!.toJson() - ) - } - QuickActionAlertDialog( title = stringResource(R.string.quick_action_request_deletion_alert_title), textContent = stringResource(R.string.quick_action_request_deletion_alert_body), @@ -439,20 +389,16 @@ fun DeleteAlertDialog(note: Note, accountViewModel: AccountViewModel, onDismiss: buttonText = stringResource(R.string.quick_action_delete_dialog_btn), onClickDoOnce = { scope.launch(Dispatchers.IO) { - event = accountViewModel.delete(note, !accountViewModel.loggedInWithAmber()) - } - if (!accountViewModel.loggedInWithAmber()) { - onDismiss() + accountViewModel.delete(note) } + onDismiss() }, onClickDontShowAgain = { scope.launch(Dispatchers.IO) { - event = accountViewModel.delete(note, !accountViewModel.loggedInWithAmber()) + accountViewModel.delete(note) accountViewModel.dontShowDeleteRequestDialog() } - if (!accountViewModel.loggedInWithAmber()) { - onDismiss() - } + onDismiss() }, onDismiss = onDismiss ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index fbe4e21d2..afa21a7e1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -77,11 +77,8 @@ import coil.compose.AsyncImage import coil.request.CachePolicy import coil.request.ImageRequest import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note -import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.ui.actions.NewPostView -import com.vitorpamplona.amethyst.ui.actions.SignerDialog import com.vitorpamplona.amethyst.ui.components.ImageUrlType import com.vitorpamplona.amethyst.ui.components.InLineIconRenderer import com.vitorpamplona.amethyst.ui.components.TextType @@ -110,7 +107,6 @@ import com.vitorpamplona.amethyst.ui.theme.TinyBorders import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.placeholderTextColorFilter -import com.vitorpamplona.quartz.events.Event import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableMap import kotlinx.coroutines.CoroutineScope @@ -647,26 +643,6 @@ fun BoostReaction( val iconButtonModifier = remember { Modifier.size(iconSize) } - var event by remember { - mutableStateOf(null) - } - - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - } - }, - data = event!!.toJson() - ) - } IconButton( modifier = iconButtonModifier, @@ -674,7 +650,7 @@ fun BoostReaction( if (accountViewModel.isWriteable()) { if (accountViewModel.hasBoosted(baseNote)) { scope.launch(Dispatchers.IO) { - accountViewModel.deleteBoostsTo(baseNote, true) + accountViewModel.deleteBoostsTo(baseNote) } } else { wantsToBoost = true @@ -683,7 +659,7 @@ fun BoostReaction( if (accountViewModel.loggedInWithAmber()) { if (accountViewModel.hasBoosted(baseNote)) { scope.launch(Dispatchers.IO) { - event = accountViewModel.deleteBoostsTo(baseNote, false) + accountViewModel.deleteBoostsTo(baseNote) } } else { wantsToBoost = true @@ -716,7 +692,7 @@ fun BoostReaction( }, onRepost = { scope.launch(Dispatchers.IO) { - event = accountViewModel.boost(baseNote, false) + accountViewModel.boost(baseNote) } } ) @@ -766,24 +742,6 @@ fun LikeReaction( var wantsToChangeReactionSymbol by remember { mutableStateOf(false) } var wantsToReact by remember { mutableStateOf(false) } - var event by remember { mutableStateOf(null) } - - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - } - }, - data = event!!.toJson() - ) - } Box( contentAlignment = Center, @@ -804,9 +762,9 @@ fun LikeReaction( if (accountViewModel.account.reactionChoices.size == 1) { val reaction = accountViewModel.account.reactionChoices.first() if (accountViewModel.hasReactedTo(baseNote, reaction)) { - event = accountViewModel.deleteReactionTo(baseNote, reaction, false) + accountViewModel.deleteReactionTo(baseNote, reaction) } else { - event = accountViewModel.reactTo(baseNote, reaction, false) + accountViewModel.reactTo(baseNote, reaction) } } else if (accountViewModel.account.reactionChoices.size > 1) { wantsToReact = true @@ -961,9 +919,9 @@ private fun likeClick( scope.launch(Dispatchers.IO) { val reaction = accountViewModel.account.reactionChoices.first() if (accountViewModel.hasReactedTo(baseNote, reaction)) { - accountViewModel.deleteReactionTo(baseNote, reaction, true) + accountViewModel.deleteReactionTo(baseNote, reaction) } else { - accountViewModel.reactTo(baseNote, reaction, true) + accountViewModel.reactTo(baseNote, reaction) } } } else if (accountViewModel.account.reactionChoices.size > 1) { @@ -1294,7 +1252,7 @@ private fun BoostTypeChoicePopup(baseNote: Note, iconSize: Dp, accountViewModel: onClick = { if (accountViewModel.isWriteable()) { scope.launch(Dispatchers.IO) { - accountViewModel.boost(baseNote, true) + accountViewModel.boost(baseNote) onDismiss() } } else { @@ -1377,40 +1335,16 @@ private fun ActionableReactionButton( toRemove: Set ) { val scope = rememberCoroutineScope() - val context = LocalContext.current - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - onDismiss() - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - onDismiss() - } - }, - data = event!!.toJson() - ) - } Button( modifier = Modifier.padding(horizontal = 3.dp), onClick = { - val loggedInWithAmber = accountViewModel.loggedInWithAmber() scope.launch(Dispatchers.IO) { - event = accountViewModel.reactToOrDelete( + accountViewModel.reactToOrDelete( baseNote, - reactionType, - !loggedInWithAmber + reactionType ) - if (!loggedInWithAmber) { - onDismiss() - } + onDismiss() } }, shape = ButtonBorder, @@ -1422,16 +1356,12 @@ private fun ActionableReactionButton( val thisModifier = remember(reactionType) { Modifier.combinedClickable( onClick = { - val loggedInWithAmber = accountViewModel.loggedInWithAmber() scope.launch(Dispatchers.IO) { - event = accountViewModel.reactToOrDelete( + accountViewModel.reactToOrDelete( baseNote, - reactionType, - !loggedInWithAmber + reactionType ) - if (!loggedInWithAmber) { - onDismiss() - } + onDismiss() } }, onLongClick = { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt index 455d1644f..1366f3ae7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt @@ -41,19 +41,15 @@ import androidx.core.content.ContextCompat import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.map import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.AmberUtils -import com.vitorpamplona.amethyst.service.relays.Client -import com.vitorpamplona.amethyst.ui.actions.SignerDialog import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImage import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.ReportNoteDialog import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.toHexKey -import com.vitorpamplona.quartz.events.Event import kotlinx.collections.immutable.ImmutableSet import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -388,31 +384,12 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState, accountVi val scope = rememberCoroutineScope() - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - onDismiss() - } - }, - data = event!!.toJson() - ) - } - if (!state.isFollowingAuthor) { DropdownMenuItem( onClick = { val author = note.author ?: return@DropdownMenuItem - event = accountViewModel.follow(author, !accountViewModel.loggedInWithAmber()) - if (!accountViewModel.loggedInWithAmber()) { + scope.launch(Dispatchers.IO) { + accountViewModel.follow(author) onDismiss() } } @@ -479,7 +456,7 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState, accountVi ) bookmarks?.decryptedContent = AmberUtils.content AmberUtils.content = "" - event = accountViewModel.removePrivateBookmark(note, bookmarks?.decryptedContent ?: "") + accountViewModel.removePrivateBookmark(note, bookmarks?.decryptedContent ?: "") } else { accountViewModel.removePrivateBookmark(note) onDismiss() @@ -501,7 +478,7 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState, accountVi ) bookmarks?.decryptedContent = AmberUtils.content AmberUtils.content = "" - event = accountViewModel.addPrivateBookmark(note, bookmarks?.decryptedContent ?: "") + accountViewModel.addPrivateBookmark(note, bookmarks?.decryptedContent ?: "") } else { accountViewModel.addPrivateBookmark(note) onDismiss() @@ -524,7 +501,7 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState, accountVi ) bookmarks?.decryptedContent = AmberUtils.content AmberUtils.content = "" - event = accountViewModel.removePublicBookmark( + accountViewModel.removePublicBookmark( note, bookmarks?.decryptedContent ?: "" ) @@ -549,7 +526,7 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState, accountVi ) bookmarks?.decryptedContent = AmberUtils.content AmberUtils.content = "" - event = accountViewModel.addPublicBookmark( + accountViewModel.addPublicBookmark( note, bookmarks?.decryptedContent ?: "" ) @@ -572,10 +549,8 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState, accountVi DropdownMenuItem( onClick = { scope.launch(Dispatchers.IO) { - event = accountViewModel.delete(note, !accountViewModel.loggedInWithAmber()) - if (!accountViewModel.loggedInWithAmber()) { - onDismiss() - } + accountViewModel.delete(note) + onDismiss() } } ) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt index 7971f7469..3e5bfa716 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt @@ -1,9 +1,6 @@ package com.vitorpamplona.amethyst.ui.note -import android.app.Activity import android.widget.Toast -import androidx.activity.compose.rememberLauncherForActivityResult -import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -29,14 +26,9 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User -import com.vitorpamplona.amethyst.service.AmberUtils -import com.vitorpamplona.amethyst.service.relays.Client -import com.vitorpamplona.amethyst.ui.actions.SignerDialog -import com.vitorpamplona.amethyst.ui.actions.SignerType import com.vitorpamplona.amethyst.ui.screen.ZapReqResponse import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.FollowButton @@ -47,9 +39,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.showAmountAxis import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.ui.theme.Size55dp import com.vitorpamplona.amethyst.ui.theme.placeholderText -import com.vitorpamplona.quartz.encoders.toHexKey -import com.vitorpamplona.quartz.events.ContactListEvent -import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.LnZapEvent import com.vitorpamplona.quartz.events.LnZapRequestEvent import kotlinx.coroutines.Dispatchers @@ -185,113 +174,11 @@ fun UserActionOptions( accountViewModel: AccountViewModel ) { val scope = rememberCoroutineScope() - val context = LocalContext.current - - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - accountViewModel.account.live.invalidateData() - accountViewModel.account.saveable.invalidateData() - event = null - } - }, - data = event!!.toJson() - ) - } - - val encryptResult = rememberLauncherForActivityResult( - contract = ActivityResultContracts.StartActivityForResult(), - onResult = { - if (it.resultCode != Activity.RESULT_OK) { - scope.launch { - Toast.makeText( - context, - "Sign request rejected", - Toast.LENGTH_SHORT - ).show() - } - return@rememberLauncherForActivityResult - } - - val encryptedContent = it.data?.getStringExtra("signature") ?: "" - event = accountViewModel.show(baseAuthor, encryptedContent) - } - ) - - val decryptResult = rememberLauncherForActivityResult( - contract = ActivityResultContracts.StartActivityForResult(), - onResult = { - if (it.resultCode != Activity.RESULT_OK) { - scope.launch { - Toast.makeText( - context, - "Sign request rejected", - Toast.LENGTH_SHORT - ).show() - } - return@rememberLauncherForActivityResult - } - - val decryptedContent = it.data?.getStringExtra("signature") ?: "" - val blockList = accountViewModel.account.getBlockList() - val privateTags = if (blockList == null) { - listOf(listOf("p", baseAuthor.pubkeyHex)) - } else { - if (accountViewModel.account.isHidden(baseAuthor)) { - blockList.privateTagsOrEmpty(decryptedContent).filter { element -> !element.contains(baseAuthor.pubkeyHex) } - } else { - blockList.privateTagsOrEmpty(decryptedContent).plus(element = listOf("p", baseAuthor.pubkeyHex)) - } - } - val msg = Event.mapper.writeValueAsString(privateTags) - - ServiceManager.shouldPauseService = true - AmberUtils.openAmber( - msg, - SignerType.NIP04_ENCRYPT, - encryptResult, - accountViewModel.account.keyPair.pubKey.toHexKey() - ) - } - ) WatchIsHiddenUser(baseAuthor, accountViewModel) { isHidden -> if (isHidden) { ShowUserButton { - if (accountViewModel.loggedInWithAmber()) { - scope.launch(Dispatchers.IO) { - val blockList = accountViewModel.account.getBlockList() - val content = blockList?.content ?: "" - if (content.isBlank()) { - val privateTags = listOf(listOf("p", baseAuthor.pubkeyHex)) - val msg = Event.mapper.writeValueAsString(privateTags) - - AmberUtils.openAmber( - msg, - SignerType.NIP04_ENCRYPT, - encryptResult, - accountViewModel.account.keyPair.pubKey.toHexKey() - ) - } else { - AmberUtils.openAmber( - content, - SignerType.NIP04_DECRYPT, - decryptResult, - accountViewModel.account.keyPair.pubKey.toHexKey() - ) - } - } - } else { - accountViewModel.show(baseAuthor) - } + accountViewModel.show(baseAuthor) } } else { ShowFollowingOrUnfollowingButton(baseAuthor, accountViewModel) @@ -321,30 +208,13 @@ fun ShowFollowingOrUnfollowingButton( } } - var event by remember { mutableStateOf(null) } - - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - } - }, - data = event!!.toJson() - ) - } - if (isFollowing) { UnfollowButton { if (!accountViewModel.isWriteable()) { if (accountViewModel.loggedInWithAmber()) { - event = accountViewModel.unfollow(baseAuthor, false) + scope.launch(Dispatchers.IO) { + accountViewModel.unfollow(baseAuthor) + } } else { scope.launch { Toast @@ -358,7 +228,7 @@ fun ShowFollowingOrUnfollowingButton( } } else { scope.launch(Dispatchers.IO) { - accountViewModel.unfollow(baseAuthor, true) + accountViewModel.unfollow(baseAuthor) } } } @@ -366,7 +236,9 @@ fun ShowFollowingOrUnfollowingButton( FollowButton { if (!accountViewModel.isWriteable()) { if (accountViewModel.loggedInWithAmber()) { - event = accountViewModel.account.follow(baseAuthor, false) + scope.launch(Dispatchers.IO) { + accountViewModel.account.follow(baseAuthor) + } } else { scope.launch { Toast @@ -380,7 +252,7 @@ fun ShowFollowingOrUnfollowingButton( } } else { scope.launch(Dispatchers.IO) { - accountViewModel.follow(baseAuthor, true) + accountViewModel.follow(baseAuthor) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index c589d75ad..e012b8e1c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -30,16 +30,11 @@ import com.vitorpamplona.amethyst.ui.note.ZapAmountCommentNotification import com.vitorpamplona.amethyst.ui.note.ZapraiserStatus import com.vitorpamplona.amethyst.ui.note.showAmount import com.vitorpamplona.quartz.encoders.HexKey -import com.vitorpamplona.quartz.events.BookmarkListEvent -import com.vitorpamplona.quartz.events.ContactListEvent -import com.vitorpamplona.quartz.events.DeletionEvent import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.GiftWrapEvent import com.vitorpamplona.quartz.events.LnZapEvent import com.vitorpamplona.quartz.events.LnZapRequestEvent import com.vitorpamplona.quartz.events.PayInvoiceErrorResponse -import com.vitorpamplona.quartz.events.PeopleListEvent -import com.vitorpamplona.quartz.events.ReactionEvent import com.vitorpamplona.quartz.events.ReportEvent import com.vitorpamplona.quartz.events.SealedGossipEvent import com.vitorpamplona.quartz.events.UserMetadata @@ -112,16 +107,16 @@ class AccountViewModel(val account: Account) : ViewModel() { return account.userProfile() } - fun reactTo(note: Note, reaction: String, signEvent: Boolean): ReactionEvent? { - return account.reactTo(note, reaction, signEvent) + fun reactTo(note: Note, reaction: String) { + account.reactTo(note, reaction) } - fun reactToOrDelete(note: Note, reaction: String, signEvent: Boolean): Event? { + fun reactToOrDelete(note: Note, reaction: String) { val currentReactions = account.reactionTo(note, reaction) if (currentReactions.isNotEmpty()) { - return account.delete(currentReactions, signEvent) + account.delete(currentReactions) } else { - return account.reactTo(note, reaction, signEvent) + account.reactTo(note, reaction) } } @@ -134,16 +129,16 @@ class AccountViewModel(val account: Account) : ViewModel() { return account.hasReacted(baseNote, reaction) } - fun deleteReactionTo(note: Note, reaction: String, signEvent: Boolean): DeletionEvent? { - return account.delete(account.reactionTo(note, reaction), signEvent) + fun deleteReactionTo(note: Note, reaction: String) { + account.delete(account.reactionTo(note, reaction)) } fun hasBoosted(baseNote: Note): Boolean { return account.hasBoosted(baseNote) } - fun deleteBoostsTo(note: Note, signEvent: Boolean): DeletionEvent? { - return account.delete(account.boostsTo(note), signEvent) + fun deleteBoostsTo(note: Note) { + account.delete(account.boostsTo(note)) } fun calculateIfNoteWasZappedByAccount(zappedNote: Note, onWasZapped: (Boolean) -> Unit) { @@ -302,8 +297,8 @@ class AccountViewModel(val account: Account) : ViewModel() { } } - fun boost(note: Note, signEvent: Boolean): Event? { - return account.boost(note, signEvent) + fun boost(note: Note) { + account.boost(note) } fun removeEmojiPack(usersEmojiList: Note, emojiList: Note) { @@ -318,24 +313,24 @@ class AccountViewModel(val account: Account) : ViewModel() { account.addPrivateBookmark(note) } - fun addPrivateBookmark(note: Note, decryptedContent: String): BookmarkListEvent? { - return account.addPrivateBookmark(note, decryptedContent) + fun addPrivateBookmark(note: Note, decryptedContent: String) { + account.addPrivateBookmark(note, decryptedContent) } - fun addPublicBookmark(note: Note, decryptedContent: String): BookmarkListEvent? { - return account.addPublicBookmark(note, decryptedContent) + fun addPublicBookmark(note: Note, decryptedContent: String) { + account.addPublicBookmark(note, decryptedContent) } - fun removePublicBookmark(note: Note, decryptedContent: String): BookmarkListEvent? { - return account.removePublicBookmark(note, decryptedContent) + fun removePublicBookmark(note: Note, decryptedContent: String) { + account.removePublicBookmark(note, decryptedContent) } fun addPublicBookmark(note: Note) { account.addPublicBookmark(note) } - fun removePrivateBookmark(note: Note, decryptedContent: String): BookmarkListEvent? { - return account.removePrivateBookmark(note, decryptedContent) + fun removePrivateBookmark(note: Note, decryptedContent: String) { + account.removePrivateBookmark(note, decryptedContent) } fun removePrivateBookmark(note: Note) { @@ -358,8 +353,8 @@ class AccountViewModel(val account: Account) : ViewModel() { account.broadcast(note) } - fun delete(note: Note, signEvent: Boolean): DeletionEvent? { - return account.delete(note, signEvent) + fun delete(note: Note) { + account.delete(note) } fun decrypt(note: Note): String? { @@ -382,12 +377,12 @@ class AccountViewModel(val account: Account) : ViewModel() { account.prefer(source, target, preference) } - fun follow(user: User, signEvent: Boolean): ContactListEvent? { - return account.follow(user, signEvent) + fun follow(user: User) { + account.follow(user) } - fun unfollow(user: User, signEvent: Boolean): ContactListEvent? { - return account.unfollow(user, signEvent) + fun unfollow(user: User) { + account.unfollow(user) } fun isLoggedUser(user: User?): Boolean { @@ -489,20 +484,12 @@ class AccountViewModel(val account: Account) : ViewModel() { return account.unseal(event) } - fun show(user: User, encryptedContent: String): PeopleListEvent? { - return account.showUser(user.pubkeyHex, encryptedContent) - } - fun show(user: User) { viewModelScope.launch(Dispatchers.IO) { account.showUser(user.pubkeyHex) } } - fun hide(user: User, encryptedContent: String): PeopleListEvent? { - return account.hideUser(user.pubkeyHex, encryptedContent) - } - fun hide(user: User) { viewModelScope.launch(Dispatchers.IO) { account.hideUser(user.pubkeyHex) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt index 15afe9fa9..46fe8e705 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt @@ -86,12 +86,10 @@ import com.vitorpamplona.amethyst.model.PublicChatChannel import com.vitorpamplona.amethyst.model.ServersAvailable import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.NostrChannelDataSource -import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.ui.actions.NewChannelView import com.vitorpamplona.amethyst.ui.actions.NewMessageTagger import com.vitorpamplona.amethyst.ui.actions.NewPostViewModel import com.vitorpamplona.amethyst.ui.actions.PostButton -import com.vitorpamplona.amethyst.ui.actions.SignerDialog import com.vitorpamplona.amethyst.ui.actions.UploadFromGallery import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy @@ -131,7 +129,6 @@ import com.vitorpamplona.amethyst.ui.theme.SmallBorder import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.StdPadding import com.vitorpamplona.amethyst.ui.theme.placeholderText -import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.ImmutableListOfLists import com.vitorpamplona.quartz.events.LiveActivitiesEvent.Companion.STATUS_LIVE import com.vitorpamplona.quartz.events.Participant @@ -263,24 +260,6 @@ fun ChannelScreen( val scope = rememberCoroutineScope() - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - } - }, - data = event!!.toJson() - ) - } - // LAST ROW EditFieldRow(newPostModel, isPrivate = false, accountViewModel = accountViewModel) { scope.launch(Dispatchers.IO) { @@ -292,22 +271,20 @@ fun ChannelScreen( ) tagger.run() if (channel is PublicChatChannel) { - event = accountViewModel.account.sendChannelMessage( + accountViewModel.account.sendChannelMessage( message = tagger.message, toChannel = channel.idHex, replyTo = tagger.replyTos, mentions = tagger.mentions, - wantsToMarkAsSensitive = false, - signEvent = !accountViewModel.loggedInWithAmber() + wantsToMarkAsSensitive = false ) } else if (channel is LiveActivitiesChannel) { - event = accountViewModel.account.sendLiveMessage( + accountViewModel.account.sendLiveMessage( message = tagger.message, toChannel = channel.address, replyTo = tagger.replyTos, mentions = tagger.mentions, - wantsToMarkAsSensitive = false, - signEvent = !accountViewModel.loggedInWithAmber() + wantsToMarkAsSensitive = false ) } newPostModel.message = TextFieldValue("") @@ -1127,30 +1104,12 @@ private fun EditButton(accountViewModel: AccountViewModel, channel: PublicChatCh @Composable fun JoinChatButton(accountViewModel: AccountViewModel, channel: Channel, nav: (String) -> Unit) { val scope = rememberCoroutineScope() - val context = LocalContext.current - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - } - }, - data = event!!.toJson() - ) - } Button( modifier = Modifier.padding(horizontal = 3.dp), onClick = { scope.launch(Dispatchers.IO) { - event = accountViewModel.account.follow(channel, !accountViewModel.loggedInWithAmber()) + accountViewModel.account.follow(channel) } }, shape = ButtonBorder, @@ -1167,30 +1126,12 @@ fun JoinChatButton(accountViewModel: AccountViewModel, channel: Channel, nav: (S @Composable fun LeaveChatButton(accountViewModel: AccountViewModel, channel: Channel, nav: (String) -> Unit) { val scope = rememberCoroutineScope() - val context = LocalContext.current - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - } - }, - data = event!!.toJson() - ) - } Button( modifier = Modifier.padding(horizontal = 3.dp), onClick = { scope.launch(Dispatchers.IO) { - event = accountViewModel.account.unfollow(channel, !accountViewModel.loggedInWithAmber()) + accountViewModel.account.unfollow(channel) } }, shape = ButtonBorder, @@ -1207,30 +1148,12 @@ fun LeaveChatButton(accountViewModel: AccountViewModel, channel: Channel, nav: ( @Composable fun JoinCommunityButton(accountViewModel: AccountViewModel, note: AddressableNote, nav: (String) -> Unit) { val scope = rememberCoroutineScope() - val context = LocalContext.current - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - } - }, - data = event!!.toJson() - ) - } Button( modifier = Modifier.padding(horizontal = 3.dp), onClick = { scope.launch(Dispatchers.IO) { - event = accountViewModel.account.follow(note, !accountViewModel.loggedInWithAmber()) + accountViewModel.account.follow(note) } }, shape = ButtonBorder, @@ -1247,30 +1170,12 @@ fun JoinCommunityButton(accountViewModel: AccountViewModel, note: AddressableNot @Composable fun LeaveCommunityButton(accountViewModel: AccountViewModel, note: AddressableNote, nav: (String) -> Unit) { val scope = rememberCoroutineScope() - val context = LocalContext.current - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - } - }, - data = event!!.toJson() - ) - } Button( modifier = Modifier.padding(horizontal = 3.dp), onClick = { scope.launch(Dispatchers.IO) { - event = accountViewModel.account.unfollow(note, !accountViewModel.loggedInWithAmber()) + accountViewModel.account.unfollow(note) } }, shape = ButtonBorder, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt index 6a7f9e0b8..7e24f7980 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt @@ -63,17 +63,13 @@ import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.map import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.ServersAvailable import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.NostrChatroomDataSource -import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.actions.NewPostViewModel import com.vitorpamplona.amethyst.ui.actions.PostButton -import com.vitorpamplona.amethyst.ui.actions.SignerDialog -import com.vitorpamplona.amethyst.ui.actions.SignerType import com.vitorpamplona.amethyst.ui.actions.UploadFromGallery import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture @@ -96,7 +92,6 @@ import com.vitorpamplona.amethyst.ui.theme.StdPadding import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.quartz.events.ChatMessageEvent import com.vitorpamplona.quartz.events.ChatroomKey -import com.vitorpamplona.quartz.events.Event import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.Dispatchers @@ -297,49 +292,6 @@ fun ChatroomScreen( val scope = rememberCoroutineScope() - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - } - }, - data = event!!.toJson() - ) - } - - var message by remember { mutableStateOf(null) } - if (message != null) { - SignerDialog( - onClose = { - message = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - event = accountViewModel.account.sendPrivateMessage( - message = it, - toUser = room.users.first(), - replyingTo = replyTo.value, - mentions = null, - wantsToMarkAsSensitive = false, - signEvent = false - ) - message = null - } - }, - data = message!!, - pubKey = room.users.first(), - type = SignerType.NIP04_ENCRYPT - ) - } - // LAST ROW PrivateMessageEditFieldRow(newPostModel, isPrivate = true, accountViewModel) { scope.launch(Dispatchers.IO) { @@ -350,22 +302,16 @@ fun ChatroomScreen( toUsers = room.users.toList(), replyingTo = replyTo.value, mentions = null, - wantsToMarkAsSensitive = false, - signEvent = true + wantsToMarkAsSensitive = false ) } else { - if (!accountViewModel.isWriteable() && accountViewModel.loggedInWithAmber()) { - message = newPostModel.message.text - } else { - accountViewModel.account.sendPrivateMessage( - message = newPostModel.message.text, - toUser = room.users.first(), - replyingTo = replyTo.value, - mentions = null, - wantsToMarkAsSensitive = false, - signEvent = true - ) - } + accountViewModel.account.sendPrivateMessage( + message = newPostModel.message.text, + toUser = room.users.first(), + replyingTo = replyTo.value, + mentions = null, + wantsToMarkAsSensitive = false + ) } newPostModel.message = TextFieldValue("") @@ -700,8 +646,7 @@ fun NewSubjectView(onClose: () -> Unit, accountViewModel: AccountViewModel, room subject = groupName.value.ifBlank { null }, replyingTo = null, mentions = null, - wantsToMarkAsSensitive = false, - signEvent = true + wantsToMarkAsSensitive = false ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt index f2fd180cf..3a35787f8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt @@ -31,15 +31,11 @@ import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.viewmodel.compose.viewModel import com.fonfon.kgeohash.toGeoHash import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.service.NostrGeohashDataSource import com.vitorpamplona.amethyst.service.ReverseGeoLocationUtil -import com.vitorpamplona.amethyst.service.relays.Client -import com.vitorpamplona.amethyst.ui.actions.SignerDialog import com.vitorpamplona.amethyst.ui.screen.NostrGeoHashFeedViewModel import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView import com.vitorpamplona.amethyst.ui.theme.StdPadding -import com.vitorpamplona.quartz.events.Event import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -171,29 +167,14 @@ fun GeoHashActionOptions( userState?.user?.isFollowingGeohashCached(tag) ?: false } } - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - } - }, - data = event!!.toJson() - ) - } if (isFollowingTag) { UnfollowButton { if (!accountViewModel.isWriteable()) { if (accountViewModel.loggedInWithAmber()) { - event = accountViewModel.account.unfollowGeohash(tag, false) + scope.launch(Dispatchers.IO) { + accountViewModel.account.unfollowGeohash(tag) + } } else { scope.launch { Toast @@ -207,7 +188,7 @@ fun GeoHashActionOptions( } } else { scope.launch(Dispatchers.IO) { - accountViewModel.account.unfollowGeohash(tag, true) + accountViewModel.account.unfollowGeohash(tag) } } } @@ -215,7 +196,9 @@ fun GeoHashActionOptions( FollowButton { if (!accountViewModel.isWriteable()) { if (accountViewModel.loggedInWithAmber()) { - event = accountViewModel.account.followGeohash(tag, false) + scope.launch(Dispatchers.IO) { + accountViewModel.account.followGeohash(tag) + } } else { scope.launch { Toast @@ -229,7 +212,7 @@ fun GeoHashActionOptions( } } else { scope.launch(Dispatchers.IO) { - accountViewModel.account.followGeohash(tag, true) + accountViewModel.account.followGeohash(tag) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt index 9c3073d35..4d609eef9 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt @@ -16,10 +16,8 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -30,14 +28,10 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.service.NostrHashtagDataSource -import com.vitorpamplona.amethyst.service.relays.Client -import com.vitorpamplona.amethyst.ui.actions.SignerDialog import com.vitorpamplona.amethyst.ui.screen.NostrHashtagFeedViewModel import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView import com.vitorpamplona.amethyst.ui.theme.StdPadding -import com.vitorpamplona.quartz.events.Event import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -149,30 +143,14 @@ fun HashtagActionOptions( userState?.user?.isFollowingHashtagCached(tag) ?: false } } - var event by remember { mutableStateOf(null) } - - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - } - }, - data = event!!.toJson() - ) - } if (isFollowingTag) { UnfollowButton { if (!accountViewModel.isWriteable()) { if (accountViewModel.loggedInWithAmber()) { - event = accountViewModel.account.unfollowHashtag(tag, false) + scope.launch(Dispatchers.IO) { + accountViewModel.account.unfollowHashtag(tag) + } } else { scope.launch { Toast @@ -186,7 +164,7 @@ fun HashtagActionOptions( } } else { scope.launch(Dispatchers.IO) { - accountViewModel.account.unfollowHashtag(tag, true) + accountViewModel.account.unfollowHashtag(tag) } } } @@ -194,7 +172,9 @@ fun HashtagActionOptions( FollowButton { if (!accountViewModel.isWriteable()) { if (accountViewModel.loggedInWithAmber()) { - event = accountViewModel.account.followHashtag(tag, false) + scope.launch(Dispatchers.IO) { + accountViewModel.account.followHashtag(tag) + } } else { scope.launch { Toast @@ -208,7 +188,7 @@ fun HashtagActionOptions( } } else { scope.launch(Dispatchers.IO) { - accountViewModel.account.followHashtag(tag, true) + accountViewModel.account.followHashtag(tag) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index d7d791b5e..67e507246 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -1,11 +1,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn -import android.app.Activity import android.content.Intent import android.net.Uri import android.widget.Toast -import androidx.activity.compose.rememberLauncherForActivityResult -import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.* @@ -56,17 +53,12 @@ import androidx.lifecycle.map import androidx.lifecycle.viewmodel.compose.viewModel import coil.compose.AsyncImage import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User -import com.vitorpamplona.amethyst.service.AmberUtils import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource -import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.ui.actions.NewUserMetadataView -import com.vitorpamplona.amethyst.ui.actions.SignerDialog -import com.vitorpamplona.amethyst.ui.actions.SignerType import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji import com.vitorpamplona.amethyst.ui.components.DisplayNip05ProfileStatus import com.vitorpamplona.amethyst.ui.components.InvoiceRequestCard @@ -101,13 +93,10 @@ import com.vitorpamplona.amethyst.ui.theme.Size16Modifier import com.vitorpamplona.amethyst.ui.theme.Size35dp import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.quartz.encoders.ATag -import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.events.AppDefinitionEvent import com.vitorpamplona.quartz.events.BadgeDefinitionEvent import com.vitorpamplona.quartz.events.BadgeProfilesEvent import com.vitorpamplona.quartz.events.ChatroomKey -import com.vitorpamplona.quartz.events.ContactListEvent -import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.GitHubIdentity import com.vitorpamplona.quartz.events.IdentityClaim import com.vitorpamplona.quartz.events.ImmutableListOfLists @@ -728,113 +717,11 @@ private fun ProfileActions( } val scope = rememberCoroutineScope() - val context = LocalContext.current - - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - accountViewModel.account.live.invalidateData() - accountViewModel.account.saveable.invalidateData() - event = null - } - }, - data = event!!.toJson() - ) - } - - val encryptResult = rememberLauncherForActivityResult( - contract = ActivityResultContracts.StartActivityForResult(), - onResult = { - if (it.resultCode != Activity.RESULT_OK) { - scope.launch { - Toast.makeText( - context, - "Sign request rejected", - Toast.LENGTH_SHORT - ).show() - } - return@rememberLauncherForActivityResult - } - - val encryptedContent = it.data?.getStringExtra("signature") ?: "" - event = accountViewModel.show(baseUser, encryptedContent) - } - ) - - val decryptResult = rememberLauncherForActivityResult( - contract = ActivityResultContracts.StartActivityForResult(), - onResult = { - if (it.resultCode != Activity.RESULT_OK) { - scope.launch { - Toast.makeText( - context, - "Sign request rejected", - Toast.LENGTH_SHORT - ).show() - } - return@rememberLauncherForActivityResult - } - - val decryptedContent = it.data?.getStringExtra("signature") ?: "" - val blockList = accountViewModel.account.getBlockList() - val privateTags = if (blockList == null) { - listOf(listOf("p", baseUser.pubkeyHex)) - } else { - if (accountViewModel.account.isHidden(baseUser)) { - blockList.privateTagsOrEmpty(decryptedContent).filter { element -> !element.contains(baseUser.pubkeyHex) } - } else { - blockList.privateTagsOrEmpty(decryptedContent).plus(element = listOf("p", baseUser.pubkeyHex)) - } - } - val msg = Event.mapper.writeValueAsString(privateTags) - - ServiceManager.shouldPauseService = true - AmberUtils.openAmber( - msg, - SignerType.NIP04_ENCRYPT, - encryptResult, - accountViewModel.account.keyPair.pubKey.toHexKey() - ) - } - ) WatchIsHiddenUser(baseUser, accountViewModel) { isHidden -> if (isHidden) { ShowUserButton { - if (accountViewModel.loggedInWithAmber()) { - scope.launch(Dispatchers.IO) { - val blockList = accountViewModel.account.getBlockList() - val content = blockList?.content ?: "" - if (content.isBlank()) { - val privateTags = listOf(listOf("p", baseUser.pubkeyHex)) - val msg = Event.mapper.writeValueAsString(privateTags) - - AmberUtils.openAmber( - msg, - SignerType.NIP04_ENCRYPT, - encryptResult, - accountViewModel.account.keyPair.pubKey.toHexKey() - ) - } else { - AmberUtils.openAmber( - content, - SignerType.NIP04_DECRYPT, - decryptResult, - accountViewModel.account.keyPair.pubKey.toHexKey() - ) - } - } - } else { - accountViewModel.showUser(baseUser.pubkeyHex) - } + accountViewModel.showUser(baseUser.pubkeyHex) } } else { DisplayFollowUnfollowButton(baseUser, accountViewModel) @@ -858,30 +745,13 @@ private fun DisplayFollowUnfollowButton( it.user.isFollowing(accountViewModel.account.userProfile()) }.distinctUntilChanged().observeAsState(initial = baseUser.isFollowing(accountViewModel.account.userProfile())) - var event by remember { mutableStateOf(null) } - - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - event = null - } - }, - data = event!!.toJson() - ) - } - if (isLoggedInFollowingUser) { UnfollowButton { if (!accountViewModel.isWriteable()) { if (accountViewModel.loggedInWithAmber()) { - event = accountViewModel.account.unfollow(baseUser, false) + scope.launch(Dispatchers.IO) { + accountViewModel.account.unfollow(baseUser) + } } else { scope.launch { Toast @@ -895,7 +765,7 @@ private fun DisplayFollowUnfollowButton( } } else { scope.launch(Dispatchers.IO) { - accountViewModel.account.unfollow(baseUser, true) + accountViewModel.account.unfollow(baseUser) } } } @@ -904,7 +774,9 @@ private fun DisplayFollowUnfollowButton( FollowButton(R.string.follow_back) { if (!accountViewModel.isWriteable()) { if (accountViewModel.loggedInWithAmber()) { - event = accountViewModel.account.follow(baseUser, false) + scope.launch(Dispatchers.IO) { + accountViewModel.account.follow(baseUser) + } } else { scope.launch { Toast @@ -918,7 +790,7 @@ private fun DisplayFollowUnfollowButton( } } else { scope.launch(Dispatchers.IO) { - accountViewModel.account.follow(baseUser, true) + accountViewModel.account.follow(baseUser) } } } @@ -926,7 +798,9 @@ private fun DisplayFollowUnfollowButton( FollowButton(R.string.follow) { if (!accountViewModel.isWriteable()) { if (accountViewModel.loggedInWithAmber()) { - event = accountViewModel.account.follow(baseUser, false) + scope.launch(Dispatchers.IO) { + accountViewModel.account.follow(baseUser) + } } else { scope.launch { Toast @@ -940,7 +814,7 @@ private fun DisplayFollowUnfollowButton( } } else { scope.launch(Dispatchers.IO) { - accountViewModel.account.follow(baseUser, true) + accountViewModel.account.follow(baseUser) } } } @@ -1828,88 +1702,6 @@ fun UserProfileDropDownMenu(user: User, popupExpanded: Boolean, onDismiss: () -> ) { val clipboardManager = LocalClipboardManager.current val scope = rememberCoroutineScope() - val context = LocalContext.current - - var event by remember { mutableStateOf(null) } - if (event != null) { - SignerDialog( - onClose = { - event = null - }, - onPost = { - scope.launch(Dispatchers.IO) { - val signedEvent = Event.fromJson(it) - Client.send(signedEvent) - LocalCache.verifyAndConsume(signedEvent, null) - accountViewModel.account.live.invalidateData() - accountViewModel.account.saveable.invalidateData() - event = null - onDismiss() - } - }, - data = event!!.toJson() - ) - } - - val encryptResult = rememberLauncherForActivityResult( - contract = ActivityResultContracts.StartActivityForResult(), - onResult = { - if (it.resultCode != Activity.RESULT_OK) { - scope.launch { - Toast.makeText( - context, - "Sign request rejected", - Toast.LENGTH_SHORT - ).show() - } - return@rememberLauncherForActivityResult - } - - val encryptedContent = it.data?.getStringExtra("signature") ?: "" - event = if (accountViewModel.account.isHidden(user)) { - accountViewModel.show(user, encryptedContent) - } else { - accountViewModel.hide(user, encryptedContent) - } - } - ) - - val decryptResult = rememberLauncherForActivityResult( - contract = ActivityResultContracts.StartActivityForResult(), - onResult = { - if (it.resultCode != Activity.RESULT_OK) { - scope.launch { - Toast.makeText( - context, - "Sign request rejected", - Toast.LENGTH_SHORT - ).show() - } - return@rememberLauncherForActivityResult - } - - val decryptedContent = it.data?.getStringExtra("signature") ?: "" - val blockList = accountViewModel.account.getBlockList() - val privateTags = if (blockList == null) { - listOf(listOf("p", user.pubkeyHex)) - } else { - if (accountViewModel.account.isHidden(user)) { - blockList.privateTagsOrEmpty(decryptedContent).filter { element -> !element.contains(user.pubkeyHex) } - } else { - blockList.privateTagsOrEmpty(decryptedContent).plus(element = listOf("p", user.pubkeyHex)) - } - } - val msg = Event.mapper.writeValueAsString(privateTags) - - ServiceManager.shouldPauseService = true - AmberUtils.openAmber( - msg, - SignerType.NIP04_ENCRYPT, - encryptResult, - accountViewModel.account.keyPair.pubKey.toHexKey() - ) - } - ) DropdownMenuItem(onClick = { clipboardManager.setText(AnnotatedString(user.pubkeyNpub())); onDismiss() }) { Text(stringResource(R.string.copy_user_id)) @@ -1920,33 +1712,8 @@ fun UserProfileDropDownMenu(user: User, popupExpanded: Boolean, onDismiss: () -> if (accountViewModel.account.isHidden(user)) { DropdownMenuItem( onClick = { - if (accountViewModel.loggedInWithAmber()) { - scope.launch(Dispatchers.IO) { - val blockList = accountViewModel.account.getBlockList() - val content = blockList?.content ?: "" - if (content.isBlank()) { - val privateTags = listOf(listOf("p", user.pubkeyHex)) - val msg = Event.mapper.writeValueAsString(privateTags) - - AmberUtils.openAmber( - msg, - SignerType.NIP04_ENCRYPT, - encryptResult, - accountViewModel.account.keyPair.pubKey.toHexKey() - ) - } else { - AmberUtils.openAmber( - content, - SignerType.NIP04_DECRYPT, - decryptResult, - accountViewModel.account.keyPair.pubKey.toHexKey() - ) - } - } - } else { - accountViewModel.show(user) - onDismiss() - } + accountViewModel.show(user) + onDismiss() } ) { Text(stringResource(R.string.unblock_user)) @@ -1954,33 +1721,8 @@ fun UserProfileDropDownMenu(user: User, popupExpanded: Boolean, onDismiss: () -> } else { DropdownMenuItem( onClick = { - if (accountViewModel.loggedInWithAmber()) { - scope.launch(Dispatchers.IO) { - val blockList = accountViewModel.account.getBlockList() - val content = blockList?.content ?: "" - if (content.isBlank()) { - val privateTags = listOf(listOf("p", user.pubkeyHex)) - val msg = Event.mapper.writeValueAsString(privateTags) - - AmberUtils.openAmber( - msg, - SignerType.NIP04_ENCRYPT, - encryptResult, - accountViewModel.account.keyPair.pubKey.toHexKey() - ) - } else { - AmberUtils.openAmber( - content, - SignerType.NIP04_DECRYPT, - decryptResult, - accountViewModel.account.keyPair.pubKey.toHexKey() - ) - } - } - } else { - accountViewModel.hide(user) - onDismiss() - } + accountViewModel.hide(user) + onDismiss() } ) { Text(stringResource(id = R.string.block_hide_user)) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt index 71411abe2..5cb89ace8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt @@ -36,15 +36,16 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.service.AmberUtils import com.vitorpamplona.amethyst.service.PackageUtils -import com.vitorpamplona.amethyst.ui.actions.SignerDialog -import com.vitorpamplona.amethyst.ui.actions.SignerType import com.vitorpamplona.amethyst.ui.qrcode.SimpleQrCodeScanner import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.ConnectOrbotDialog import com.vitorpamplona.amethyst.ui.theme.Font14SP import com.vitorpamplona.amethyst.ui.theme.Size35dp import com.vitorpamplona.amethyst.ui.theme.placeholderText +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import java.util.* @OptIn(ExperimentalComposeUiApi::class) @@ -65,7 +66,7 @@ fun LoginPage( val useProxy = remember { mutableStateOf(false) } val proxyPort = remember { mutableStateOf("9050") } var connectOrbotDialogOpen by remember { mutableStateOf(false) } - var loginWithAmber by remember { mutableStateOf(false) } + val scope = rememberCoroutineScope() Column( modifier = Modifier @@ -258,37 +259,6 @@ fun LoginPage( } } - if (loginWithAmber) { - SignerDialog( - onClose = { - loginWithAmber = false - }, - onPost = { - key.value = TextFieldValue(it) - if (!acceptedTerms.value) { - termsAcceptanceIsRequired = - context.getString(R.string.acceptance_of_terms_is_required) - } - - if (key.value.text.isBlank()) { - errorMessage = context.getString(R.string.key_is_required) - } - - if (acceptedTerms.value && key.value.text.isNotBlank()) { - try { - accountViewModel.startUI(key.value.text, useProxy.value, proxyPort.value.toInt(), true) - } catch (e: Exception) { - Log.e("Login", "Could not sign in", e) - errorMessage = context.getString(R.string.invalid_key) - } - } - loginWithAmber = false - }, - data = "", - type = SignerType.GET_PUBLIC_KEY - ) - } - Spacer(modifier = Modifier.height(20.dp)) Box(modifier = Modifier.padding(40.dp, 0.dp, 40.dp, 0.dp)) { @@ -329,7 +299,27 @@ fun LoginPage( Box(modifier = Modifier.padding(40.dp, 40.dp, 40.dp, 0.dp)) { Button( onClick = { - loginWithAmber = true + scope.launch(Dispatchers.IO) { + AmberUtils.loginWithAmber() + key.value = TextFieldValue(AmberUtils.content) + if (!acceptedTerms.value) { + termsAcceptanceIsRequired = + context.getString(R.string.acceptance_of_terms_is_required) + } + + if (key.value.text.isBlank()) { + errorMessage = context.getString(R.string.key_is_required) + } + + if (acceptedTerms.value && key.value.text.isNotBlank()) { + try { + accountViewModel.startUI(key.value.text, useProxy.value, proxyPort.value.toInt(), true) + } catch (e: Exception) { + Log.e("Login", "Could not sign in", e) + errorMessage = context.getString(R.string.invalid_key) + } + } + } }, shape = RoundedCornerShape(Size35dp), modifier = Modifier diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/BookmarkListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/BookmarkListEvent.kt index 094f9b491..f99f837bf 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/BookmarkListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/BookmarkListEvent.kt @@ -81,5 +81,11 @@ class BookmarkListEvent( val sig = CryptoUtils.sign(id, privateKey) return BookmarkListEvent(id.toHexKey(), pubKey.toHexKey(), createdAt, tags, content, sig.toHexKey()) } + + fun create( + unsignedEvent: BookmarkListEvent, signature: String + ): BookmarkListEvent { + return BookmarkListEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) + } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/ChannelCreateEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/ChannelCreateEvent.kt index 5bf523f4c..28e43f9f2 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/ChannelCreateEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/ChannelCreateEvent.kt @@ -2,10 +2,12 @@ package com.vitorpamplona.quartz.events import android.util.Log import androidx.compose.runtime.Immutable +import androidx.compose.runtime.key import com.fasterxml.jackson.module.kotlin.readValue import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.crypto.CryptoUtils +import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.HexKey @Immutable @@ -27,7 +29,7 @@ class ChannelCreateEvent( companion object { const val kind = 40 - fun create(channelInfo: ChannelData?, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): ChannelCreateEvent { + fun create(channelInfo: ChannelData?, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): ChannelCreateEvent { val content = try { if (channelInfo != null) { mapper.writeValueAsString(channelInfo) @@ -39,11 +41,15 @@ class ChannelCreateEvent( "" } - val pubKey = CryptoUtils.pubkeyCreate(privateKey).toHexKey() + val pubKey = keyPair.pubKey.toHexKey() val tags = emptyList>() val id = generateId(pubKey, createdAt, kind, tags, content) - val sig = CryptoUtils.sign(id, privateKey) - return ChannelCreateEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig.toHexKey()) + val sig = if (keyPair.privKey == null) null else CryptoUtils.sign(id, keyPair.pubKey) + return ChannelCreateEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig?.toHexKey() ?: "") + } + + fun create(unsignedEvent: ChannelCreateEvent, signature: String): ChannelCreateEvent { + return ChannelCreateEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/ChannelMessageEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/ChannelMessageEvent.kt index 1bf5f57c4..07e33ca71 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/ChannelMessageEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/ChannelMessageEvent.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.crypto.CryptoUtils +import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.HexKey @Immutable @@ -33,8 +34,7 @@ class ChannelMessageEvent( replyTos: List? = null, mentions: List? = null, zapReceiver: String?, - pubKey: HexKey, - privateKey: ByteArray?, + keyPair: KeyPair, createdAt: Long = TimeUtils.now(), markAsSensitive: Boolean, zapRaiserAmount: Long?, @@ -63,10 +63,17 @@ class ChannelMessageEvent( tags.add(listOf("g", it)) } + val pubKey = keyPair.pubKey.toHexKey() val id = generateId(pubKey, createdAt, kind, tags, content) - val sig = if (privateKey == null) null else CryptoUtils.sign(id, privateKey) + val sig = if (keyPair.privKey == null) null else CryptoUtils.sign(id, keyPair.privKey) return ChannelMessageEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig?.toHexKey() ?: "") } + + fun create( + unsignedEvent: ChannelMessageEvent, signature: String + ): ChannelMessageEvent { + return ChannelMessageEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) + } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/ChannelMetadataEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/ChannelMetadataEvent.kt index 19067905d..245397b59 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/ChannelMetadataEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/ChannelMetadataEvent.kt @@ -5,6 +5,7 @@ import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.crypto.CryptoUtils +import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.HexKey @Immutable @@ -29,7 +30,7 @@ class ChannelMetadataEvent( companion object { const val kind = 41 - fun create(newChannelInfo: ChannelCreateEvent.ChannelData?, originalChannelIdHex: String, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): ChannelMetadataEvent { + fun create(newChannelInfo: ChannelCreateEvent.ChannelData?, originalChannelIdHex: String, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): ChannelMetadataEvent { val content = if (newChannelInfo != null) { mapper.writeValueAsString(newChannelInfo) @@ -37,11 +38,15 @@ class ChannelMetadataEvent( "" } - val pubKey = CryptoUtils.pubkeyCreate(privateKey).toHexKey() + val pubKey = keyPair.pubKey.toHexKey() val tags = listOf(listOf("e", originalChannelIdHex, "", "root")) val id = generateId(pubKey, createdAt, kind, tags, content) - val sig = CryptoUtils.sign(id, privateKey) - return ChannelMetadataEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig.toHexKey()) + val sig = if (keyPair.privKey == null) null else CryptoUtils.sign(id, keyPair.privKey) + return ChannelMetadataEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig?.toHexKey() ?: "") + } + + fun create(unsignedEvent: ChannelMetadataEvent, signature: String): ChannelMetadataEvent { + return ChannelMetadataEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/ContactListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/ContactListEvent.kt index 895977bd1..df3aa0275 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/ContactListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/ContactListEvent.kt @@ -261,6 +261,20 @@ class ContactListEvent( ) } + fun create( + unsignedEvent: Event, + signature: String + ): ContactListEvent { + return ContactListEvent( + unsignedEvent.id, + unsignedEvent.pubKey, + unsignedEvent.createdAt, + unsignedEvent.tags, + unsignedEvent.content, + signature + ) + } + fun create( content: String, tags: List>, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/DeletionEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/DeletionEvent.kt index 6d7f8a485..05b4faa93 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/DeletionEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/DeletionEvent.kt @@ -29,5 +29,9 @@ class DeletionEvent( val sig = if (keyPair.privKey == null) null else CryptoUtils.sign(id, keyPair.privKey) return DeletionEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig?.toHexKey() ?: "") } + + fun create(unsignedEvent: DeletionEvent, signature: String): DeletionEvent { + return DeletionEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) + } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/GenericRepostEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/GenericRepostEvent.kt index 51f1a7354..adbea501e 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/GenericRepostEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/GenericRepostEvent.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.crypto.CryptoUtils +import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.HexKey @Immutable @@ -28,12 +29,13 @@ class GenericRepostEvent( companion object { const val kind = 16 - fun create(boostedPost: EventInterface, pubKey: HexKey, createdAt: Long = TimeUtils.now()): GenericRepostEvent { + fun create(boostedPost: EventInterface, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): GenericRepostEvent { val content = boostedPost.toJson() val replyToPost = listOf("e", boostedPost.id()) val replyToAuthor = listOf("p", boostedPost.pubKey()) + val pubKey = keyPair.pubKey.toHexKey() var tags: List> = listOf(replyToPost, replyToAuthor) if (boostedPost is AddressableEvent) { @@ -43,27 +45,12 @@ class GenericRepostEvent( tags = tags + listOf(listOf("k", "${boostedPost.kind()}")) val id = generateId(pubKey, createdAt, kind, tags, content) - return GenericRepostEvent(id.toHexKey(), pubKey, createdAt, tags, content, "") + val sig = if (keyPair.privKey == null) null else CryptoUtils.sign(id, keyPair.privKey) + return GenericRepostEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig?.toHexKey() ?: "") } - fun create(boostedPost: EventInterface, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): GenericRepostEvent { - val content = boostedPost.toJson() - - val replyToPost = listOf("e", boostedPost.id()) - val replyToAuthor = listOf("p", boostedPost.pubKey()) - - val pubKey = CryptoUtils.pubkeyCreate(privateKey).toHexKey() - var tags: List> = listOf(replyToPost, replyToAuthor) - - if (boostedPost is AddressableEvent) { - tags = tags + listOf(listOf("a", boostedPost.address().toTag())) - } - - tags = tags + listOf(listOf("k", "${boostedPost.kind()}")) - - val id = generateId(pubKey, createdAt, kind, tags, content) - val sig = CryptoUtils.sign(id, privateKey) - return GenericRepostEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig.toHexKey()) + fun create(unsignedEvent: GenericRepostEvent, signature: String): GenericRepostEvent { + return GenericRepostEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/HTTPAuthorizationEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/HTTPAuthorizationEvent.kt index ea9896e18..c22abc29e 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/HTTPAuthorizationEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/HTTPAuthorizationEvent.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.crypto.CryptoUtils +import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.HexKey @Immutable @@ -23,7 +24,7 @@ class HTTPAuthorizationEvent( url: String, method: String, body: String? = null, - privateKey: ByteArray, + keyPair: KeyPair, createdAt: Long = TimeUtils.now() ): HTTPAuthorizationEvent { var hash = "" @@ -37,10 +38,16 @@ class HTTPAuthorizationEvent( listOf("payload", hash) ) - val pubKey = CryptoUtils.pubkeyCreate(privateKey).toHexKey() + val pubKey = keyPair.pubKey.toHexKey() val id = generateId(pubKey, createdAt, kind, tags, "") - val sig = CryptoUtils.sign(id, privateKey) - return HTTPAuthorizationEvent(id.toHexKey(), pubKey, createdAt, tags, "", sig.toHexKey()) + val sig = if (keyPair.privKey == null) null else CryptoUtils.sign(id, keyPair.privKey) + return HTTPAuthorizationEvent(id.toHexKey(), pubKey, createdAt, tags, "", sig?.toHexKey() ?: "") + } + + fun create( + unsignedEvent: HTTPAuthorizationEvent, signature: String + ): HTTPAuthorizationEvent { + return HTTPAuthorizationEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/LiveActivitiesChatMessageEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/LiveActivitiesChatMessageEvent.kt index 1160dd6ca..3e84f3526 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/LiveActivitiesChatMessageEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/LiveActivitiesChatMessageEvent.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.crypto.CryptoUtils +import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.ATag import com.vitorpamplona.quartz.encoders.HexKey @@ -49,8 +50,7 @@ class LiveActivitiesChatMessageEvent( replyTos: List? = null, mentions: List? = null, zapReceiver: String?, - pubKey: HexKey, - privateKey: ByteArray?, + keyPair: KeyPair, createdAt: Long = TimeUtils.now(), markAsSensitive: Boolean, zapRaiserAmount: Long?, @@ -79,9 +79,16 @@ class LiveActivitiesChatMessageEvent( tags.add(listOf("g", it)) } + val pubKey = keyPair.pubKey.toHexKey() val id = generateId(pubKey, createdAt, kind, tags, content) - val sig = if (privateKey == null) null else CryptoUtils.sign(id, privateKey) + val sig = if (keyPair.privKey == null) null else CryptoUtils.sign(id, keyPair.privKey) return LiveActivitiesChatMessageEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig?.toHexKey() ?: "") } + + fun create( + unsignedEvent: LiveActivitiesChatMessageEvent, signature: String + ): LiveActivitiesChatMessageEvent { + return LiveActivitiesChatMessageEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) + } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/MetadataEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/MetadataEvent.kt index 490cb826f..6bc69ddbc 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/MetadataEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/MetadataEvent.kt @@ -160,5 +160,9 @@ class MetadataEvent( val sig = if (privateKey == null) null else CryptoUtils.sign(id, privateKey) return MetadataEvent(id.toHexKey(), pubKey, createdAt, tags, contactMetaData, sig?.toHexKey() ?: "") } + + fun create(unsignedEvent: MetadataEvent, signature: String): MetadataEvent { + return MetadataEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) + } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/PeopleListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/PeopleListEvent.kt index 80a05057b..b3e814fcd 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/PeopleListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/PeopleListEvent.kt @@ -228,5 +228,9 @@ class PeopleListEvent( val id = generateId(pubKey, createdAt, kind, tags, content) return PeopleListEvent(id.toHexKey(), pubKey, createdAt, tags, content, "") } + + fun create(unsignedEvent: PeopleListEvent, signature: String): PeopleListEvent { + return PeopleListEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) + } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/PollNoteEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/PollNoteEvent.kt index 4c926f1ba..6b63e4e23 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/PollNoteEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/PollNoteEvent.kt @@ -93,6 +93,12 @@ class PollNoteEvent( val sig = if (privateKey == null) null else CryptoUtils.sign(id, privateKey) return PollNoteEvent(id.toHexKey(), pubKey, createdAt, tags, msg, sig?.toHexKey() ?: "") } + + fun create( + unsignedEvent: PollNoteEvent, signature: String + ): PollNoteEvent { + return PollNoteEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) + } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/PrivateDmEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/PrivateDmEvent.kt index 296947527..0d7e99ac1 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/PrivateDmEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/PrivateDmEvent.kt @@ -5,6 +5,7 @@ import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.crypto.CryptoUtils +import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.HexValidator import com.vitorpamplona.quartz.encoders.Hex @@ -86,8 +87,7 @@ class PrivateDmEvent( replyTos: List? = null, mentions: List? = null, zapReceiver: String?, - pubKey: HexKey, - privateKey: ByteArray?, + keyPair: KeyPair, createdAt: Long = TimeUtils.now(), publishedRecipientPubKey: ByteArray? = null, advertiseNip18: Boolean = true, @@ -96,9 +96,9 @@ class PrivateDmEvent( geohash: String? = null ): PrivateDmEvent { val message = if (advertiseNip18) { nip18Advertisement } else { "" } + msg - val content = if (privateKey == null) message else CryptoUtils.encryptNIP04( + val content = if (keyPair.privKey == null) message else CryptoUtils.encryptNIP04( message, - privateKey, + keyPair.privKey, recipientPubKey ) val tags = mutableListOf>() @@ -124,9 +124,17 @@ class PrivateDmEvent( tags.add(listOf("g", it)) } + val pubKey = keyPair.pubKey.toHexKey() val id = generateId(pubKey, createdAt, kind, tags, content) - val sig = if (privateKey == null) null else CryptoUtils.sign(id, privateKey) + val sig = if (keyPair.privKey == null) null else CryptoUtils.sign(id, keyPair.privKey) return PrivateDmEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig?.toHexKey() ?: "") } + + fun create( + unsignedEvent: PrivateDmEvent, + signature: String, + ): PrivateDmEvent { + return PrivateDmEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) + } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/ReactionEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/ReactionEvent.kt index 6218f9c73..fcf8a1a9e 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/ReactionEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/ReactionEvent.kt @@ -61,5 +61,9 @@ class ReactionEvent( val sig = if (keyPair.privKey == null) null else CryptoUtils.sign(id, keyPair.privKey) return ReactionEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig?.toHexKey() ?: "") } + + fun create(unsignedEvent: ReactionEvent, signature: String): ReactionEvent { + return ReactionEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) + } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/RelayAuthEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/RelayAuthEvent.kt index ba8cd6835..6cb829cae 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/RelayAuthEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/RelayAuthEvent.kt @@ -32,5 +32,9 @@ class RelayAuthEvent( val sig = if (privateKey == null) null else CryptoUtils.sign(id, privateKey) return RelayAuthEvent(id.toHexKey(), localPubKey, createdAt, tags, content, sig?.toHexKey() ?: "") } + + fun create(unsignedEvent: RelayAuthEvent, signature: String): RelayAuthEvent { + return RelayAuthEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) + } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/RepostEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/RepostEvent.kt index 5f9b542bd..0a09b98e3 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/RepostEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/RepostEvent.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.crypto.CryptoUtils +import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.HexKey @Immutable @@ -28,12 +29,13 @@ class RepostEvent( companion object { const val kind = 6 - fun create(boostedPost: EventInterface, pubKey: HexKey, createdAt: Long = TimeUtils.now()): RepostEvent { + fun create(boostedPost: EventInterface, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): RepostEvent { val content = boostedPost.toJson() val replyToPost = listOf("e", boostedPost.id()) val replyToAuthor = listOf("p", boostedPost.pubKey()) + val pubKey = keyPair.pubKey.toHexKey() var tags: List> = listOf(replyToPost, replyToAuthor) if (boostedPost is AddressableEvent) { @@ -41,25 +43,12 @@ class RepostEvent( } val id = generateId(pubKey, createdAt, kind, tags, content) - return RepostEvent(id.toHexKey(), pubKey, createdAt, tags, content, "") + val sig = if (keyPair.privKey == null) null else CryptoUtils.sign(id, keyPair.privKey) + return RepostEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig?.toHexKey() ?: "") } - fun create(boostedPost: EventInterface, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): RepostEvent { - val content = boostedPost.toJson() - - val replyToPost = listOf("e", boostedPost.id()) - val replyToAuthor = listOf("p", boostedPost.pubKey()) - - val pubKey = CryptoUtils.pubkeyCreate(privateKey).toHexKey() - var tags: List> = listOf(replyToPost, replyToAuthor) - - if (boostedPost is AddressableEvent) { - tags = tags + listOf(listOf("a", boostedPost.address().toTag())) - } - - val id = generateId(pubKey, createdAt, kind, tags, content) - val sig = CryptoUtils.sign(id, privateKey) - return RepostEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig.toHexKey()) + fun create(unsignedEvent: RepostEvent, signature: String): RepostEvent { + return RepostEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) } } } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/TextNoteEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/TextNoteEvent.kt index 288b034ce..ebcd393c1 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/TextNoteEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/TextNoteEvent.kt @@ -100,6 +100,13 @@ class TextNoteEvent( val sig = if (keyPair.privKey == null) null else CryptoUtils.sign(id, keyPair.privKey) return TextNoteEvent(id.toHexKey(), pubKey, createdAt, tags, msg, sig?.toHexKey() ?: "") } + + fun create( + unsignedEvent: TextNoteEvent, signature: String + ): TextNoteEvent { + + return TextNoteEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature) + } } }