add signerDialog in the profile screen follow button
This commit is contained in:
@@ -460,7 +460,11 @@ class Account(
|
|||||||
if (followingCommunities.isNotEmpty()) {
|
if (followingCommunities.isNotEmpty()) {
|
||||||
followingCommunities.forEach {
|
followingCommunities.forEach {
|
||||||
ATag.parse(it, null)?.let {
|
ATag.parse(it, null)?.let {
|
||||||
returningContactList = ContactListEvent.followAddressableEvent(returningContactList, it, keyPair.privKey!!)
|
returningContactList = if (keyPair.privKey == null) {
|
||||||
|
ContactListEvent.followAddressableEvent(returningContactList, it, keyPair.pubKey.toHexKey())
|
||||||
|
} else {
|
||||||
|
ContactListEvent.followAddressableEvent(returningContactList, it, keyPair.privKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
followingCommunities = emptySet()
|
followingCommunities = emptySet()
|
||||||
@@ -468,7 +472,11 @@ class Account(
|
|||||||
|
|
||||||
if (followingChannels.isNotEmpty()) {
|
if (followingChannels.isNotEmpty()) {
|
||||||
followingChannels.forEach {
|
followingChannels.forEach {
|
||||||
returningContactList = ContactListEvent.followEvent(returningContactList, it, keyPair.privKey!!)
|
returningContactList = if (keyPair.privKey == null) {
|
||||||
|
ContactListEvent.followEvent(returningContactList, it, keyPair.pubKey.toHexKey())
|
||||||
|
} else {
|
||||||
|
ContactListEvent.followEvent(returningContactList, it, keyPair.privKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
followingChannels = emptySet()
|
followingChannels = emptySet()
|
||||||
}
|
}
|
||||||
@@ -476,13 +484,17 @@ class Account(
|
|||||||
return returningContactList
|
return returningContactList
|
||||||
}
|
}
|
||||||
|
|
||||||
fun follow(user: User) {
|
fun follow(user: User, signEvent: Boolean = true): ContactListEvent? {
|
||||||
if (!isWriteable()) return
|
if (!isWriteable() && signEvent) return null
|
||||||
|
|
||||||
val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList)
|
val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList)
|
||||||
|
|
||||||
val event = if (contactList != null) {
|
val event = if (contactList != null) {
|
||||||
ContactListEvent.followUser(contactList, user.pubkeyHex, keyPair.privKey!!)
|
if (signEvent) {
|
||||||
|
ContactListEvent.followUser(contactList, user.pubkeyHex, keyPair.privKey!!)
|
||||||
|
} else {
|
||||||
|
ContactListEvent.followUser(contactList, user.pubkeyHex, keyPair.pubKey.toHexKey())
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ContactListEvent.createFromScratch(
|
ContactListEvent.createFromScratch(
|
||||||
followUsers = listOf(Contact(user.pubkeyHex, null)),
|
followUsers = listOf(Contact(user.pubkeyHex, null)),
|
||||||
@@ -491,12 +503,18 @@ class Account(
|
|||||||
followCommunities = emptyList(),
|
followCommunities = emptyList(),
|
||||||
followEvents = DefaultChannels.toList(),
|
followEvents = DefaultChannels.toList(),
|
||||||
relayUse = Constants.defaultRelays.associate { it.url to ContactListEvent.ReadWrite(it.read, it.write) },
|
relayUse = Constants.defaultRelays.associate { it.url to ContactListEvent.ReadWrite(it.read, it.write) },
|
||||||
privateKey = keyPair.privKey!!
|
privateKey = keyPair.privKey!!,
|
||||||
|
publicKey = keyPair.pubKey
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!signEvent) {
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
Client.send(event)
|
Client.send(event)
|
||||||
LocalCache.consume(event)
|
LocalCache.consume(event)
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun follow(channel: Channel) {
|
fun follow(channel: Channel) {
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.vitorpamplona.amethyst.service
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
|
||||||
|
object PackageUtils {
|
||||||
|
fun isPackageInstalled(context: Context, target: String): Boolean {
|
||||||
|
return context.packageManager.getInstalledApplications(0).find { info -> info.packageName == target } != null
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -98,7 +98,8 @@ class ContactListEvent(
|
|||||||
followEvents: List<String>,
|
followEvents: List<String>,
|
||||||
relayUse: Map<String, ReadWrite>?,
|
relayUse: Map<String, ReadWrite>?,
|
||||||
privateKey: ByteArray,
|
privateKey: ByteArray,
|
||||||
createdAt: Long = TimeUtils.now()
|
createdAt: Long = TimeUtils.now(),
|
||||||
|
publicKey: ByteArray? = null
|
||||||
): ContactListEvent {
|
): ContactListEvent {
|
||||||
val content = if (relayUse != null) {
|
val content = if (relayUse != null) {
|
||||||
gson.toJson(relayUse)
|
gson.toJson(relayUse)
|
||||||
@@ -126,10 +127,29 @@ class ContactListEvent(
|
|||||||
listOf("g", it)
|
listOf("g", it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (publicKey == null) {
|
||||||
|
return create(
|
||||||
|
content = content,
|
||||||
|
tags = tags,
|
||||||
|
privateKey = privateKey,
|
||||||
|
createdAt = createdAt
|
||||||
|
)
|
||||||
|
}
|
||||||
return create(
|
return create(
|
||||||
content = content,
|
content = content,
|
||||||
tags = tags,
|
tags = tags,
|
||||||
privateKey = privateKey,
|
pubKey = publicKey.toHexKey(),
|
||||||
|
createdAt = createdAt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun followUser(earlierVersion: ContactListEvent, pubKeyHex: String, pubKey: HexKey, createdAt: Long = TimeUtils.now()): ContactListEvent {
|
||||||
|
if (earlierVersion.isTaggedUser(pubKeyHex)) return earlierVersion
|
||||||
|
|
||||||
|
return create(
|
||||||
|
content = earlierVersion.content,
|
||||||
|
tags = earlierVersion.tags.plus(element = listOf("p", pubKeyHex)),
|
||||||
|
pubKey = pubKey,
|
||||||
createdAt = createdAt
|
createdAt = createdAt
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -211,6 +231,17 @@ class ContactListEvent(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun followEvent(earlierVersion: ContactListEvent, idHex: String, pubKey: HexKey, createdAt: Long = TimeUtils.now()): ContactListEvent {
|
||||||
|
if (earlierVersion.isTaggedEvent(idHex)) return earlierVersion
|
||||||
|
|
||||||
|
return create(
|
||||||
|
content = earlierVersion.content,
|
||||||
|
tags = earlierVersion.tags.plus(element = listOf("e", idHex)),
|
||||||
|
pubKey = pubKey,
|
||||||
|
createdAt = createdAt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun unfollowEvent(earlierVersion: ContactListEvent, idHex: String, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): ContactListEvent {
|
fun unfollowEvent(earlierVersion: ContactListEvent, idHex: String, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): ContactListEvent {
|
||||||
if (!earlierVersion.isTaggedEvent(idHex)) return earlierVersion
|
if (!earlierVersion.isTaggedEvent(idHex)) return earlierVersion
|
||||||
|
|
||||||
@@ -233,6 +264,17 @@ class ContactListEvent(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun followAddressableEvent(earlierVersion: ContactListEvent, aTag: ATag, pubKey: HexKey, createdAt: Long = TimeUtils.now()): ContactListEvent {
|
||||||
|
if (earlierVersion.isTaggedAddressableNote(aTag.toTag())) return earlierVersion
|
||||||
|
|
||||||
|
return create(
|
||||||
|
content = earlierVersion.content,
|
||||||
|
tags = earlierVersion.tags.plus(element = listOfNotNull("a", aTag.toTag(), aTag.relay)),
|
||||||
|
pubKey = pubKey,
|
||||||
|
createdAt = createdAt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun unfollowAddressableEvent(earlierVersion: ContactListEvent, aTag: ATag, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): ContactListEvent {
|
fun unfollowAddressableEvent(earlierVersion: ContactListEvent, aTag: ATag, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): ContactListEvent {
|
||||||
if (!earlierVersion.isTaggedAddressableNote(aTag.toTag())) return earlierVersion
|
if (!earlierVersion.isTaggedAddressableNote(aTag.toTag())) return earlierVersion
|
||||||
|
|
||||||
@@ -259,6 +301,11 @@ class ContactListEvent(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun create(content: String, tags: List<List<String>>, pubKey: HexKey, createdAt: Long = TimeUtils.now()): ContactListEvent {
|
||||||
|
val id = generateId(pubKey, createdAt, kind, tags, content)
|
||||||
|
return ContactListEvent(id.toHexKey(), pubKey, createdAt, tags, content, "")
|
||||||
|
}
|
||||||
|
|
||||||
fun create(content: String, tags: List<List<String>>, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): ContactListEvent {
|
fun create(content: String, tags: List<List<String>>, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): ContactListEvent {
|
||||||
val pubKey = CryptoUtils.pubkeyCreate(privateKey).toHexKey()
|
val pubKey = CryptoUtils.pubkeyCreate(privateKey).toHexKey()
|
||||||
val id = generateId(pubKey, createdAt, kind, tags, content)
|
val id = generateId(pubKey, createdAt, kind, tags, content)
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ fun openAmber(
|
|||||||
@Composable
|
@Composable
|
||||||
fun SignerDialog(
|
fun SignerDialog(
|
||||||
onClose: () -> Unit,
|
onClose: () -> Unit,
|
||||||
onPost: () -> Unit,
|
onPost: (signedEvent: Event) -> Unit,
|
||||||
event: Event
|
event: Event
|
||||||
) {
|
) {
|
||||||
var signature by remember { mutableStateOf("") }
|
var signature by remember { mutableStateOf("") }
|
||||||
@@ -120,7 +120,26 @@ fun SignerDialog(
|
|||||||
|
|
||||||
PostButton(
|
PostButton(
|
||||||
onPost = {
|
onPost = {
|
||||||
onPost()
|
val signedEvent = Event(
|
||||||
|
event.id,
|
||||||
|
event.pubKey,
|
||||||
|
event.createdAt,
|
||||||
|
event.kind,
|
||||||
|
event.tags,
|
||||||
|
event.content,
|
||||||
|
signature
|
||||||
|
)
|
||||||
|
if (!signedEvent.hasValidSignature()) {
|
||||||
|
scope.launch {
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
"Invalid signature",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
return@PostButton
|
||||||
|
}
|
||||||
|
onPost(signedEvent)
|
||||||
},
|
},
|
||||||
isActive = true
|
isActive = true
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -59,16 +59,21 @@ import com.vitorpamplona.amethyst.model.LocalCache
|
|||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource
|
import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource
|
||||||
|
import com.vitorpamplona.amethyst.service.PackageUtils
|
||||||
import com.vitorpamplona.amethyst.service.model.ATag
|
import com.vitorpamplona.amethyst.service.model.ATag
|
||||||
import com.vitorpamplona.amethyst.service.model.AppDefinitionEvent
|
import com.vitorpamplona.amethyst.service.model.AppDefinitionEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.BadgeDefinitionEvent
|
import com.vitorpamplona.amethyst.service.model.BadgeDefinitionEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.BadgeProfilesEvent
|
import com.vitorpamplona.amethyst.service.model.BadgeProfilesEvent
|
||||||
|
import com.vitorpamplona.amethyst.service.model.ContactListEvent
|
||||||
|
import com.vitorpamplona.amethyst.service.model.Event
|
||||||
import com.vitorpamplona.amethyst.service.model.IdentityClaim
|
import com.vitorpamplona.amethyst.service.model.IdentityClaim
|
||||||
import com.vitorpamplona.amethyst.service.model.PayInvoiceErrorResponse
|
import com.vitorpamplona.amethyst.service.model.PayInvoiceErrorResponse
|
||||||
import com.vitorpamplona.amethyst.service.model.PayInvoiceSuccessResponse
|
import com.vitorpamplona.amethyst.service.model.PayInvoiceSuccessResponse
|
||||||
import com.vitorpamplona.amethyst.service.model.ReportEvent
|
import com.vitorpamplona.amethyst.service.model.ReportEvent
|
||||||
|
import com.vitorpamplona.amethyst.service.relays.Client
|
||||||
import com.vitorpamplona.amethyst.ui.actions.ImmutableListOfLists
|
import com.vitorpamplona.amethyst.ui.actions.ImmutableListOfLists
|
||||||
import com.vitorpamplona.amethyst.ui.actions.NewUserMetadataView
|
import com.vitorpamplona.amethyst.ui.actions.NewUserMetadataView
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.SignerDialog
|
||||||
import com.vitorpamplona.amethyst.ui.actions.toImmutableListOfLists
|
import com.vitorpamplona.amethyst.ui.actions.toImmutableListOfLists
|
||||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||||
import com.vitorpamplona.amethyst.ui.components.DisplayNip05ProfileStatus
|
import com.vitorpamplona.amethyst.ui.components.DisplayNip05ProfileStatus
|
||||||
@@ -742,6 +747,24 @@ private fun DisplayFollowUnfollowButton(
|
|||||||
it.user.isFollowing(accountViewModel.account.userProfile())
|
it.user.isFollowing(accountViewModel.account.userProfile())
|
||||||
}.distinctUntilChanged().observeAsState(initial = baseUser.isFollowing(accountViewModel.account.userProfile()))
|
}.distinctUntilChanged().observeAsState(initial = baseUser.isFollowing(accountViewModel.account.userProfile()))
|
||||||
|
|
||||||
|
var event by remember { mutableStateOf<ContactListEvent?>(null) }
|
||||||
|
|
||||||
|
if (event != null) {
|
||||||
|
SignerDialog(
|
||||||
|
onClose = {
|
||||||
|
event = null
|
||||||
|
},
|
||||||
|
onPost = {
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
Client.send(it)
|
||||||
|
LocalCache.verifyAndConsume(it, null)
|
||||||
|
event = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
event = event!!
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (isLoggedInFollowingUser) {
|
if (isLoggedInFollowingUser) {
|
||||||
UnfollowButton {
|
UnfollowButton {
|
||||||
if (!accountViewModel.isWriteable()) {
|
if (!accountViewModel.isWriteable()) {
|
||||||
@@ -782,14 +805,18 @@ private fun DisplayFollowUnfollowButton(
|
|||||||
} else {
|
} else {
|
||||||
FollowButton(R.string.follow) {
|
FollowButton(R.string.follow) {
|
||||||
if (!accountViewModel.isWriteable()) {
|
if (!accountViewModel.isWriteable()) {
|
||||||
scope.launch {
|
if (PackageUtils.isPackageInstalled(context, "com.greenart7c3.nostrsigner")) {
|
||||||
Toast
|
event = accountViewModel.account.follow(baseUser, false)
|
||||||
.makeText(
|
} else {
|
||||||
context,
|
scope.launch {
|
||||||
context.getString(R.string.login_with_a_private_key_to_be_able_to_follow),
|
Toast
|
||||||
Toast.LENGTH_SHORT
|
.makeText(
|
||||||
)
|
context,
|
||||||
.show()
|
context.getString(R.string.login_with_a_private_key_to_be_able_to_follow),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
scope.launch(Dispatchers.IO) {
|
scope.launch(Dispatchers.IO) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.screen.loggedOff
|
package com.vitorpamplona.amethyst.ui.screen.loggedOff
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
@@ -37,6 +36,7 @@ import androidx.compose.ui.text.style.TextAlign
|
|||||||
import androidx.compose.ui.text.style.TextDecoration
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
|
import com.vitorpamplona.amethyst.service.PackageUtils
|
||||||
import com.vitorpamplona.amethyst.ui.qrcode.SimpleQrCodeScanner
|
import com.vitorpamplona.amethyst.ui.qrcode.SimpleQrCodeScanner
|
||||||
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
|
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ConnectOrbotDialog
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ConnectOrbotDialog
|
||||||
@@ -229,7 +229,7 @@ fun LoginPage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPackageInstalled(context, "org.torproject.android")) {
|
if (PackageUtils.isPackageInstalled(context, "org.torproject.android")) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Checkbox(
|
Checkbox(
|
||||||
checked = useProxy.value,
|
checked = useProxy.value,
|
||||||
@@ -315,7 +315,3 @@ fun LoginPage(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isPackageInstalled(context: Context, target: String): Boolean {
|
|
||||||
return context.packageManager.getInstalledApplications(0).find { info -> info.packageName == target } != null
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user