add support for deletion events
This commit is contained in:
@@ -432,8 +432,8 @@ class Account(
|
|||||||
LocalCache.consume(event, null)
|
LocalCache.consume(event, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun delete(note: Note) {
|
fun delete(note: Note, signEvent: Boolean = true): DeletionEvent? {
|
||||||
delete(listOf(note))
|
return delete(listOf(note), signEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun delete(notes: List<Note>, signEvent: Boolean = true): DeletionEvent? {
|
fun delete(notes: List<Note>, signEvent: Boolean = true): DeletionEvent? {
|
||||||
@@ -442,11 +442,10 @@ class Account(
|
|||||||
val myNotes = notes.filter { it.author == userProfile() }.map { it.idHex }
|
val myNotes = notes.filter { it.author == userProfile() }.map { it.idHex }
|
||||||
|
|
||||||
if (myNotes.isNotEmpty()) {
|
if (myNotes.isNotEmpty()) {
|
||||||
|
val event = DeletionEvent.create(myNotes, keyPair)
|
||||||
if (!signEvent) {
|
if (!signEvent) {
|
||||||
return DeletionEvent.create(myNotes, keyPair.pubKey.toHexKey())
|
return event
|
||||||
}
|
}
|
||||||
|
|
||||||
val event = DeletionEvent.create(myNotes, keyPair.privKey!!)
|
|
||||||
Client.send(event)
|
Client.send(event)
|
||||||
LocalCache.consume(event)
|
LocalCache.consume(event)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ private fun EditStatusBox(baseAccountUser: User, accountViewModel: AccountViewMo
|
|||||||
UserStatusDeleteButton() {
|
UserStatusDeleteButton() {
|
||||||
scope.launch(Dispatchers.IO) {
|
scope.launch(Dispatchers.IO) {
|
||||||
accountViewModel.updateStatus(it, "")
|
accountViewModel.updateStatus(it, "")
|
||||||
accountViewModel.delete(it)
|
accountViewModel.delete(it, true)
|
||||||
focusManager.clearFocus(true)
|
focusManager.clearFocus(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,11 @@ import androidx.compose.material.icons.filled.Report
|
|||||||
import androidx.compose.material.icons.filled.Share
|
import androidx.compose.material.icons.filled.Share
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.shadow
|
import androidx.compose.ui.draw.shadow
|
||||||
@@ -60,13 +62,17 @@ import androidx.core.content.ContextCompat
|
|||||||
import androidx.core.graphics.ColorUtils
|
import androidx.core.graphics.ColorUtils
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.AddressableNote
|
import com.vitorpamplona.amethyst.model.AddressableNote
|
||||||
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
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.components.SelectTextDialog
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ReportNoteDialog
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ReportNoteDialog
|
||||||
import com.vitorpamplona.amethyst.ui.theme.WarningColor
|
import com.vitorpamplona.amethyst.ui.theme.WarningColor
|
||||||
import com.vitorpamplona.amethyst.ui.theme.secondaryButtonBackground
|
import com.vitorpamplona.amethyst.ui.theme.secondaryButtonBackground
|
||||||
import com.vitorpamplona.quartz.events.AudioTrackEvent
|
import com.vitorpamplona.quartz.events.AudioTrackEvent
|
||||||
|
import com.vitorpamplona.quartz.events.Event
|
||||||
import com.vitorpamplona.quartz.events.FileHeaderEvent
|
import com.vitorpamplona.quartz.events.FileHeaderEvent
|
||||||
import com.vitorpamplona.quartz.events.PeopleListEvent
|
import com.vitorpamplona.quartz.events.PeopleListEvent
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -200,6 +206,25 @@ private fun RenderMainPopup(
|
|||||||
val isOwnNote = accountViewModel.isLoggedUser(note.author)
|
val isOwnNote = accountViewModel.isLoggedUser(note.author)
|
||||||
val isFollowingUser = !isOwnNote && accountViewModel.isFollowing(note.author)
|
val isFollowingUser = !isOwnNote && accountViewModel.isFollowing(note.author)
|
||||||
|
|
||||||
|
var event by remember { mutableStateOf<Event?>(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) {
|
Popup(onDismissRequest = onDismiss, alignment = Alignment.Center) {
|
||||||
Card(
|
Card(
|
||||||
modifier = Modifier.shadow(elevation = 6.dp, shape = cardShape),
|
modifier = Modifier.shadow(elevation = 6.dp, shape = cardShape),
|
||||||
@@ -275,8 +300,10 @@ private fun RenderMainPopup(
|
|||||||
) {
|
) {
|
||||||
if (accountViewModel.hideDeleteRequestDialog) {
|
if (accountViewModel.hideDeleteRequestDialog) {
|
||||||
scope.launch(Dispatchers.IO) {
|
scope.launch(Dispatchers.IO) {
|
||||||
accountViewModel.delete(note)
|
event = accountViewModel.delete(note, !accountViewModel.loggedInWithAmber())
|
||||||
onDismiss()
|
if (!accountViewModel.loggedInWithAmber()) {
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showDeleteAlertDialog.value = true
|
showDeleteAlertDialog.value = true
|
||||||
@@ -382,6 +409,25 @@ fun NoteQuickActionItem(icon: ImageVector, label: String, onClick: () -> Unit) {
|
|||||||
fun DeleteAlertDialog(note: Note, accountViewModel: AccountViewModel, onDismiss: () -> Unit) {
|
fun DeleteAlertDialog(note: Note, accountViewModel: AccountViewModel, onDismiss: () -> Unit) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
var event by remember { mutableStateOf<Event?>(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(
|
QuickActionAlertDialog(
|
||||||
title = stringResource(R.string.quick_action_request_deletion_alert_title),
|
title = stringResource(R.string.quick_action_request_deletion_alert_title),
|
||||||
textContent = stringResource(R.string.quick_action_request_deletion_alert_body),
|
textContent = stringResource(R.string.quick_action_request_deletion_alert_body),
|
||||||
@@ -389,16 +435,20 @@ fun DeleteAlertDialog(note: Note, accountViewModel: AccountViewModel, onDismiss:
|
|||||||
buttonText = stringResource(R.string.quick_action_delete_dialog_btn),
|
buttonText = stringResource(R.string.quick_action_delete_dialog_btn),
|
||||||
onClickDoOnce = {
|
onClickDoOnce = {
|
||||||
scope.launch(Dispatchers.IO) {
|
scope.launch(Dispatchers.IO) {
|
||||||
accountViewModel.delete(note)
|
event = accountViewModel.delete(note, !accountViewModel.loggedInWithAmber())
|
||||||
|
}
|
||||||
|
if (!accountViewModel.loggedInWithAmber()) {
|
||||||
|
onDismiss()
|
||||||
}
|
}
|
||||||
onDismiss()
|
|
||||||
},
|
},
|
||||||
onClickDontShowAgain = {
|
onClickDontShowAgain = {
|
||||||
scope.launch(Dispatchers.IO) {
|
scope.launch(Dispatchers.IO) {
|
||||||
accountViewModel.delete(note)
|
event = accountViewModel.delete(note, !accountViewModel.loggedInWithAmber())
|
||||||
accountViewModel.dontShowDeleteRequestDialog()
|
accountViewModel.dontShowDeleteRequestDialog()
|
||||||
}
|
}
|
||||||
onDismiss()
|
if (!accountViewModel.loggedInWithAmber()) {
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onDismiss = onDismiss
|
onDismiss = onDismiss
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -531,7 +531,16 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState<Boolean>, accountVi
|
|||||||
}
|
}
|
||||||
Divider()
|
Divider()
|
||||||
if (state.isLoggedUser) {
|
if (state.isLoggedUser) {
|
||||||
DropdownMenuItem(onClick = { scope.launch(Dispatchers.IO) { accountViewModel.delete(note); onDismiss() } }) {
|
DropdownMenuItem(
|
||||||
|
onClick = {
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
event = accountViewModel.delete(note, !accountViewModel.loggedInWithAmber())
|
||||||
|
if (!accountViewModel.loggedInWithAmber()) {
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
Text(stringResource(R.string.request_deletion))
|
Text(stringResource(R.string.request_deletion))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -264,8 +264,8 @@ class AccountViewModel(val account: Account) : ViewModel() {
|
|||||||
account.broadcast(note)
|
account.broadcast(note)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun delete(note: Note) {
|
fun delete(note: Note, signEvent: Boolean): DeletionEvent? {
|
||||||
account.delete(note)
|
return account.delete(note, signEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decrypt(note: Note): String? {
|
fun decrypt(note: Note): String? {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import androidx.compose.runtime.Immutable
|
|||||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
import com.vitorpamplona.quartz.encoders.toHexKey
|
import com.vitorpamplona.quartz.encoders.toHexKey
|
||||||
import com.vitorpamplona.quartz.crypto.CryptoUtils
|
import com.vitorpamplona.quartz.crypto.CryptoUtils
|
||||||
|
import com.vitorpamplona.quartz.crypto.KeyPair
|
||||||
import com.vitorpamplona.quartz.encoders.HexKey
|
import com.vitorpamplona.quartz.encoders.HexKey
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -20,20 +21,13 @@ class DeletionEvent(
|
|||||||
companion object {
|
companion object {
|
||||||
const val kind = 5
|
const val kind = 5
|
||||||
|
|
||||||
fun create(deleteEvents: List<String>, pubKey: HexKey, createdAt: Long = TimeUtils.now()): DeletionEvent {
|
fun create(deleteEvents: List<String>, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): DeletionEvent {
|
||||||
val content = ""
|
val content = ""
|
||||||
|
val pubKey = keyPair.pubKey.toHexKey()
|
||||||
val tags = deleteEvents.map { listOf("e", it) }
|
val tags = deleteEvents.map { listOf("e", it) }
|
||||||
val id = generateId(pubKey, createdAt, kind, tags, content)
|
val id = generateId(pubKey, createdAt, kind, tags, content)
|
||||||
return DeletionEvent(id.toHexKey(), pubKey, createdAt, tags, content, "")
|
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(deleteEvents: List<String>, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): DeletionEvent {
|
|
||||||
val content = ""
|
|
||||||
val pubKey = CryptoUtils.pubkeyCreate(privateKey).toHexKey()
|
|
||||||
val tags = deleteEvents.map { listOf("e", it) }
|
|
||||||
val id = generateId(pubKey, createdAt, kind, tags, content)
|
|
||||||
val sig = CryptoUtils.sign(id, privateKey)
|
|
||||||
return DeletionEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig.toHexKey())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user