remove drafts from shared prefs

This commit is contained in:
greenart7c3
2024-03-15 10:38:22 -03:00
parent 8ade5b7e5f
commit 99e9514d6c
7 changed files with 17 additions and 176 deletions
@@ -107,8 +107,6 @@ private object PrefKeys {
const val LOGIN_WITH_EXTERNAL_SIGNER = "login_with_external_signer" const val LOGIN_WITH_EXTERNAL_SIGNER = "login_with_external_signer"
const val AUTOMATICALLY_SHOW_PROFILE_PICTURE = "automatically_show_profile_picture" const val AUTOMATICALLY_SHOW_PROFILE_PICTURE = "automatically_show_profile_picture"
const val SIGNER_PACKAGE_NAME = "signer_package_name" const val SIGNER_PACKAGE_NAME = "signer_package_name"
const val NEW_POST_DRAFT = "draft_new_post"
const val DRAFT_REPLY_POST = "draft_reply_post"
const val HAS_DONATED_IN_VERSION = "has_donated_in_version" const val HAS_DONATED_IN_VERSION = "has_donated_in_version"
const val PENDING_ATTESTATIONS = "pending_attestations" const val PENDING_ATTESTATIONS = "pending_attestations"
@@ -395,38 +393,6 @@ object LocalPreferences {
} }
} }
fun saveDraft(
message: String,
replyPost: String?,
account: Account,
) {
val prefs = encryptedPreferences(account.keyPair.pubKey.toNpub())
with(prefs.edit()) {
putString(PrefKeys.NEW_POST_DRAFT, message)
putString(PrefKeys.DRAFT_REPLY_POST, replyPost)
apply()
}
}
fun loadReplyDraft(account: Account): String? {
val prefs = encryptedPreferences(account.keyPair.pubKey.toNpub())
return prefs.getString(PrefKeys.DRAFT_REPLY_POST, null)
}
fun loadDraft(account: Account): String? {
val prefs = encryptedPreferences(account.keyPair.pubKey.toNpub())
return prefs.getString(PrefKeys.NEW_POST_DRAFT, null)
}
fun clearDraft(account: Account) {
val prefs = encryptedPreferences(account.keyPair.pubKey.toNpub())
with(prefs.edit()) {
remove(PrefKeys.DRAFT_REPLY_POST)
remove(PrefKeys.NEW_POST_DRAFT)
apply()
}
}
suspend fun innerLoadCurrentAccountFromEncryptedStorage(npub: String?): Account? = suspend fun innerLoadCurrentAccountFromEncryptedStorage(npub: String?): Account? =
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
checkNotInMainThread() checkNotInMainThread()
@@ -155,6 +155,15 @@ object LocalCache {
return null return null
} }
fun draftNotes(draftTag: String): List<Note> {
return notes.values.filter {
it.event?.tags()?.filter { it.size > 1 && it[0] == "d" }?.map {
Log.d("tag", it[1])
it[1]
}?.firstOrNull() == draftTag
}
}
fun getOrCreateUser(key: HexKey): User { fun getOrCreateUser(key: HexKey): User {
// checkNotInMainThread() // checkNotInMainThread()
@@ -263,7 +263,7 @@ class Relay(
val subscriptionId = msgArray.get(1).asText() val subscriptionId = msgArray.get(1).asText()
val event = Event.fromJson(msgArray.get(2)) val event = Event.fromJson(msgArray.get(2))
Log.w("Relay", "Relay onEVENT ${event.kind} $url, $subscriptionId ${msgArray.get(2)}") // Log.w("Relay", "Relay onEVENT ${event.kind} $url, $subscriptionId ${msgArray.get(2)}")
listeners.forEach { listeners.forEach {
it.onEvent( it.onEvent(
this@Relay, this@Relay,
@@ -64,7 +64,6 @@ import androidx.compose.material.icons.filled.Sell
import androidx.compose.material.icons.filled.ShowChart import androidx.compose.material.icons.filled.ShowChart
import androidx.compose.material.icons.filled.Visibility import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.material.icons.filled.VisibilityOff
import androidx.compose.material.icons.outlined.Bolt
import androidx.compose.material.icons.rounded.Warning import androidx.compose.material.icons.rounded.Warning
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
@@ -125,10 +124,8 @@ import coil.compose.AsyncImage
import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState import com.google.accompanist.permissions.rememberPermissionState
import com.vitorpamplona.amethyst.LocalPreferences
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.RichTextParser import com.vitorpamplona.amethyst.commons.RichTextParser
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.Nip96MediaServers import com.vitorpamplona.amethyst.service.Nip96MediaServers
@@ -204,17 +201,7 @@ fun NewPostView(
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
launch(Dispatchers.IO) { launch(Dispatchers.IO) {
val replyDraft = LocalPreferences.loadReplyDraft(accountViewModel.account) postViewModel.load(accountViewModel, baseReplyTo, quote, fork, version)
if (replyDraft.isNullOrBlank()) {
postViewModel.load(accountViewModel, baseReplyTo, quote, fork, version)
} else {
val note = LocalCache.checkGetOrCreateNote(replyDraft)
if (note == null) {
postViewModel.load(accountViewModel, baseReplyTo, quote, fork, version)
} else {
postViewModel.load(accountViewModel, note, quote, fork, version)
}
}
postViewModel.imageUploadingError.collect { error -> postViewModel.imageUploadingError.collect { error ->
withContext(Dispatchers.Main) { Toast.makeText(context, error, Toast.LENGTH_SHORT).show() } withContext(Dispatchers.Main) { Toast.makeText(context, error, Toast.LENGTH_SHORT).show() }
@@ -35,7 +35,6 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.fonfon.kgeohash.toGeoHash import com.fonfon.kgeohash.toGeoHash
import com.vitorpamplona.amethyst.LocalPreferences
import com.vitorpamplona.amethyst.commons.RichTextParser import com.vitorpamplona.amethyst.commons.RichTextParser
import com.vitorpamplona.amethyst.commons.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.insertUrlAtCursor
import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.Account
@@ -229,13 +228,6 @@ open class NewPostViewModel() : ViewModel() {
forwardZapTo = Split() forwardZapTo = Split()
forwardZapToEditting = TextFieldValue("") forwardZapToEditting = TextFieldValue("")
viewModelScope.launch(Dispatchers.IO) {
val draft = loadDraft()
if (draft != null) {
message = TextFieldValue(draft)
updateMessage(message)
}
}
quote?.let { quote?.let {
message = TextFieldValue(message.text + "\nnostr:${it.toNEvent()}") message = TextFieldValue(message.text + "\nnostr:${it.toNEvent()}")
urlPreview = findUrlInMessage() urlPreview = findUrlInMessage()
@@ -685,7 +677,7 @@ open class NewPostViewModel() : ViewModel() {
originalNote = null originalNote = null
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
clearDraft() accountViewModel?.deleteDraft(draftTag)
} }
NostrSearchEventOrUserDataSource.clear() NostrSearchEventOrUserDataSource.clear()
@@ -707,16 +699,6 @@ open class NewPostViewModel() : ViewModel() {
sendPost(localDraft = draftTag) sendPost(localDraft = draftTag)
} }
open fun loadDraft(): String? {
account?.let { return LocalPreferences.loadDraft(it) }
return null
}
open fun clearDraft() {
account?.let { LocalPreferences.clearDraft(it) }
}
open fun updateMessage(it: TextFieldValue) { open fun updateMessage(it: TextFieldValue) {
message = it message = it
urlPreview = findUrlInMessage() urlPreview = findUrlInMessage()
@@ -26,13 +26,11 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@@ -40,7 +38,6 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
@@ -52,12 +49,9 @@ import androidx.compose.material3.DrawerState
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalDrawerSheet import androidx.compose.material3.ModalDrawerSheet
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -83,26 +77,19 @@ import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextDirection
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import coil.compose.AsyncImage import coil.compose.AsyncImage
import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.BuildConfig
import com.vitorpamplona.amethyst.LocalPreferences
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.relays.RelayPool import com.vitorpamplona.amethyst.service.relays.RelayPool
import com.vitorpamplona.amethyst.service.relays.RelayPoolStatus import com.vitorpamplona.amethyst.service.relays.RelayPoolStatus
import com.vitorpamplona.amethyst.ui.actions.CloseButton
import com.vitorpamplona.amethyst.ui.actions.NewPostView import com.vitorpamplona.amethyst.ui.actions.NewPostView
import com.vitorpamplona.amethyst.ui.actions.NewRelayListView import com.vitorpamplona.amethyst.ui.actions.NewRelayListView
import com.vitorpamplona.amethyst.ui.actions.PostButton
import com.vitorpamplona.amethyst.ui.components.ClickableText import com.vitorpamplona.amethyst.ui.components.ClickableText
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
@@ -479,17 +466,8 @@ fun ListContent(
mutableStateOf<String?>(null) mutableStateOf<String?>(null)
} }
var showDraft by remember { mutableStateOf(false) }
var wantsToPost by remember { mutableStateOf(false) } var wantsToPost by remember { mutableStateOf(false) }
LaunchedEffect(drawerState.isOpen) {
if (drawerState.isOpen) {
launch(Dispatchers.IO) {
draftText = LocalPreferences.loadDraft(accountViewModel.account)
}
}
}
Column( Column(
modifier = modifier =
modifier modifier
@@ -566,18 +544,6 @@ fun ListContent(
}, },
) )
draftText?.let {
IconRow(
title = stringResource(R.string.edit_draft),
icon = R.drawable.ic_lists,
tint = MaterialTheme.colorScheme.onBackground,
onClick = {
coroutineScope.launch { drawerState.close() }
showDraft = true
},
)
}
NavigationRow( NavigationRow(
title = stringResource(R.string.settings), title = stringResource(R.string.settings),
icon = Route.Settings.icon, icon = Route.Settings.icon,
@@ -634,24 +600,6 @@ fun ListContent(
) )
} }
if (showDraft) {
EditDraftDialog(
{
draftText = null
showDraft = false
},
{
coroutineScope.launch(Dispatchers.IO) {
LocalPreferences.saveDraft(it, null, accountViewModel.account)
draftText = null
showDraft = false
wantsToPost = true
}
},
draftText!!,
)
}
if (disconnectTorDialog) { if (disconnectTorDialog) {
AlertDialog( AlertDialog(
title = { Text(text = stringResource(R.string.do_you_really_want_to_disable_tor_title)) }, title = { Text(text = stringResource(R.string.do_you_really_want_to_disable_tor_title)) },
@@ -679,62 +627,6 @@ fun ListContent(
} }
} }
@Composable
fun EditDraftDialog(
onClose: () -> Unit,
onPost: (String) -> Unit,
draftText: String,
) {
var message by remember {
mutableStateOf(TextFieldValue(draftText))
}
Dialog(
onDismissRequest = onClose,
properties = DialogProperties(usePlatformDefaultWidth = false),
) {
Surface(modifier = Modifier.fillMaxSize()) {
Column(
modifier = Modifier.padding(10.dp),
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth(),
) {
CloseButton(onPress = { onClose() })
PostButton(isActive = true, onPost = { onPost(message.text) })
}
Column(
modifier = Modifier.padding(8.dp),
) {
OutlinedTextField(
value = message,
onValueChange = { message = it },
keyboardOptions =
KeyboardOptions.Default.copy(
capitalization = KeyboardCapitalization.Sentences,
),
modifier =
Modifier.fillMaxWidth()
.border(
width = 1.dp,
color = MaterialTheme.colorScheme.surface,
shape = RoundedCornerShape(8.dp),
),
colors =
OutlinedTextFieldDefaults.colors(
focusedBorderColor = Color.Transparent,
unfocusedBorderColor = Color.Transparent,
),
textStyle = LocalTextStyle.current.copy(textDirection = TextDirection.Content),
)
}
}
}
}
}
@Composable @Composable
private fun RelayStatus(accountViewModel: AccountViewModel) { private fun RelayStatus(accountViewModel: AccountViewModel) {
val connectedRelaysText by RelayPool.statusFlow.collectAsStateWithLifecycle(RelayPoolStatus(0, 0)) val connectedRelaysText by RelayPool.statusFlow.collectAsStateWithLifecycle(RelayPoolStatus(0, 0))
@@ -1318,6 +1318,11 @@ class AccountViewModel(val account: Account, val settings: SettingsState) : View
} }
} }
} }
suspend fun deleteDraft(draftTag: String) {
val notes = LocalCache.draftNotes(draftTag)
account.delete(notes)
}
} }
class HasNotificationDot(bottomNavigationItems: ImmutableList<Route>) { class HasNotificationDot(bottomNavigationItems: ImmutableList<Route>) {