add remember my choice switch

This commit is contained in:
greenart7c3
2023-09-06 10:45:44 -03:00
parent b0b8199e4c
commit a11b8a852c
5 changed files with 134 additions and 10 deletions
@@ -9,6 +9,7 @@ import com.greenart7c3.nostrsigner.models.toHexKey
import com.greenart7c3.nostrsigner.service.KeyPair
import com.greenart7c3.nostrsigner.service.toNpub
import fr.acinq.secp256k1.jni.BuildConfig
import org.json.JSONObject
import java.io.File
// Release mode (!BuildConfig.DEBUG) always uses encrypted preferences
@@ -22,6 +23,7 @@ private object PrefKeys {
const val SAVED_ACCOUNTS = "all_saved_accounts"
const val NOSTR_PRIVKEY = "nostr_privkey"
const val NOSTR_PUBKEY = "nostr_pubkey"
const val REMEMBER_APPS = "remember_apps"
}
object LocalPreferences {
@@ -151,6 +153,8 @@ object LocalPreferences {
prefs.edit().apply {
account.keyPair.privKey.let { putString(PrefKeys.NOSTR_PRIVKEY, it.toHexKey()) }
account.keyPair.pubKey.let { putString(PrefKeys.NOSTR_PUBKEY, it.toHexKey()) }
val jsonObject = JSONObject(account.savedApps.toMap())
putString(PrefKeys.REMEMBER_APPS, jsonObject.toString())
}.apply()
}
@@ -163,8 +167,21 @@ object LocalPreferences {
val pubKey = getString(PrefKeys.NOSTR_PUBKEY, null) ?: return null
val privKey = getString(PrefKeys.NOSTR_PRIVKEY, null)
val jsonString = getString(PrefKeys.REMEMBER_APPS, null)
val outputMap = mutableMapOf<String, Boolean>()
if (jsonString != null) {
val jsonObject = JSONObject(jsonString)
val keysItr: Iterator<String> = jsonObject.keys()
while (keysItr.hasNext()) {
val key = keysItr.next()
val value: Boolean = jsonObject.getBoolean(key)
outputMap[key] = value
}
}
return Account(
keyPair = KeyPair(privKey = privKey?.hexToByteArray(), pubKey = pubKey.hexToByteArray())
keyPair = KeyPair(privKey = privKey?.hexToByteArray(), pubKey = pubKey.hexToByteArray()),
savedApps = outputMap
)
}
}
@@ -7,7 +7,8 @@ import com.greenart7c3.nostrsigner.service.KeyPair
@Stable
class Account(
val keyPair: KeyPair
val keyPair: KeyPair,
val savedApps: MutableMap<String, Boolean>
) {
val saveable: AccountLiveData = AccountLiveData(this)
}
@@ -52,9 +52,9 @@ class AccountStateViewModel : ViewModel() {
fun startUI(key: String) {
val account = if (key.startsWith("nsec")) {
Account(KeyPair(privKey = key.bechToBytes()))
Account(KeyPair(privKey = key.bechToBytes()), mutableMapOf())
} else {
Account(KeyPair(Hex.decode(key)))
Account(KeyPair(Hex.decode(key)), mutableMapOf())
}
LocalPreferences.updatePrefsForLogin(account)
@@ -62,16 +62,14 @@ class AccountStateViewModel : ViewModel() {
}
fun newKey() {
val account = Account(KeyPair())
val account = Account(KeyPair(), mutableMapOf())
LocalPreferences.updatePrefsForLogin(account)
startUI(account)
}
@OptIn(DelicateCoroutinesApi::class)
fun startUI(account: Account) {
if (account.keyPair.privKey != null) {
_accountContent.update { AccountState.LoggedIn(account) }
}
_accountContent.update { AccountState.LoggedIn(account) }
GlobalScope.launch(Dispatchers.Main) {
account.saveable.observeForever(saveListener)
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.widget.Toast
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -22,6 +23,7 @@ import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Scaffold
import androidx.compose.material.Switch
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccessTime
@@ -31,6 +33,8 @@ import androidx.compose.material.icons.filled.Person
import androidx.compose.material.rememberDrawerState
import androidx.compose.material.rememberScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -49,6 +53,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.LocalPreferences
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.models.Account
import com.greenart7c3.nostrsigner.models.IntentData
@@ -76,7 +81,6 @@ fun MainScreen(account: Account, accountStateViewModel: AccountStateViewModel, j
val coroutineScope = rememberCoroutineScope()
val context = LocalContext.current
val clipboardManager = LocalClipboardManager.current
Scaffold(
scaffoldState = scaffoldState,
drawerContent = {
@@ -107,7 +111,15 @@ fun MainScreen(account: Account, accountStateViewModel: AccountStateViewModel, j
val appName = packageName ?: it.name
when (it.type) {
SignerType.GET_PUBLIC_KEY -> {
val key = "$packageName-public-key"
val remember = remember {
mutableStateOf(account.savedApps[key] ?: false)
}
val shouldRunOnAccept = account.savedApps[key] ?: false
LoginWithPubKey(
shouldRunOnAccept,
remember,
packageName,
appName,
{
val sig = account.keyPair.pubKey.toNpub()
@@ -115,6 +127,8 @@ fun MainScreen(account: Account, accountStateViewModel: AccountStateViewModel, j
coroutineScope.launch {
val activity = context.getAppCompatActivity()
if (packageName != null) {
account.savedApps[key] = remember.value
LocalPreferences.saveToEncryptedStorage(account)
val intent = Intent()
intent.putExtra("signature", sig)
activity?.setResult(RESULT_OK, intent)
@@ -136,7 +150,19 @@ fun MainScreen(account: Account, accountStateViewModel: AccountStateViewModel, j
)
}
SignerType.NIP04_DECRYPT, SignerType.NIP04_ENCRYPT -> {
val key = if (it.type == SignerType.NIP04_DECRYPT) {
"$packageName-decryptnip4"
} else {
"$packageName-encryptnip4"
}
val remember = remember {
mutableStateOf(account.savedApps[key] ?: false)
}
val shouldRunOnAccept = account.savedApps[key] ?: false
EncryptDecryptData(
shouldRunOnAccept,
remember,
packageName,
appName,
it.type,
{
@@ -157,6 +183,8 @@ fun MainScreen(account: Account, accountStateViewModel: AccountStateViewModel, j
coroutineScope.launch {
val activity = context.getAppCompatActivity()
if (packageName != null) {
account.savedApps[key] = remember.value
LocalPreferences.saveToEncryptedStorage(account)
val intent = Intent()
intent.putExtra("signature", sig)
activity?.setResult(RESULT_OK, intent)
@@ -190,8 +218,15 @@ fun MainScreen(account: Account, accountStateViewModel: AccountStateViewModel, j
}
else -> {
val event = IntentUtils.getIntent(it.data, account.keyPair)
val key = "$packageName-${event.kind}"
val remember = remember {
mutableStateOf(account.savedApps[key] ?: false)
}
val shouldRunOnAccept = account.savedApps[key] ?: false
EventData(
shouldRunOnAccept,
remember,
packageName,
appName,
event,
event.toJson(),
@@ -213,6 +248,8 @@ fun MainScreen(account: Account, accountStateViewModel: AccountStateViewModel, j
coroutineScope.launch {
val activity = context.getAppCompatActivity()
if (packageName != null) {
account.savedApps[key] = remember.value
LocalPreferences.saveToEncryptedStorage(account)
val intent = Intent()
val signedEvent = Event(event.id, event.pubKey, event.createdAt, event.kind, event.tags, event.content, sig)
intent.putExtra("event", signedEvent.toJson())
@@ -251,6 +288,41 @@ fun AppTitle(appName: String) {
)
}
@Composable
fun RememberMyChoice(
shouldRunOnAccept: Boolean,
remember: MutableState<Boolean>,
packageName: String?,
onAccept: () -> Unit
) {
if (shouldRunOnAccept) {
LaunchedEffect(Unit) {
onAccept()
}
}
if (packageName != null) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clickable {
remember.value = !remember.value
}
) {
Text(
modifier = Modifier.weight(1f),
text = "Remember my choice and don't ask again"
)
Switch(
checked = remember.value,
onCheckedChange = {
remember.value = !remember.value
}
)
}
}
}
@Composable
fun AcceptRejectButtons(
onAccept: () -> Unit,
@@ -280,6 +352,9 @@ fun AcceptRejectButtons(
@Composable
fun EncryptDecryptData(
shouldRunOnAccept: Boolean,
remember: MutableState<Boolean>,
packageName: String?,
appName: String,
type: SignerType,
onAccept: () -> Unit,
@@ -307,6 +382,13 @@ fun EncryptDecryptData(
Spacer(modifier = Modifier.weight(1f))
RememberMyChoice(
shouldRunOnAccept,
remember,
packageName,
onAccept
)
AcceptRejectButtons(
onAccept,
onReject
@@ -316,6 +398,9 @@ fun EncryptDecryptData(
@Composable
fun LoginWithPubKey(
shouldRunOnAccept: Boolean,
remember: MutableState<Boolean>,
packageName: String?,
appName: String,
onAccept: () -> Unit,
onReject: () -> Unit
@@ -344,6 +429,13 @@ fun LoginWithPubKey(
Spacer(modifier = Modifier.weight(1f))
RememberMyChoice(
shouldRunOnAccept,
remember,
packageName,
onAccept
)
AcceptRejectButtons(
onAccept,
onReject
@@ -353,6 +445,9 @@ fun LoginWithPubKey(
@Composable
fun EventData(
shouldRunOnAccept: Boolean,
remember: MutableState<Boolean>,
packageName: String?,
appName: String,
event: Event,
rawJson: String,
@@ -428,6 +523,13 @@ fun EventData(
Spacer(modifier = Modifier.weight(1f))
}
RememberMyChoice(
shouldRunOnAccept,
remember,
packageName,
onAccept
)
AcceptRejectButtons(
onAccept,
onReject
@@ -3,6 +3,8 @@ package com.greenart7c3.nostrsigner.ui.previews
import android.annotation.SuppressLint
import androidx.compose.material.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.tooling.preview.Preview
import com.greenart7c3.nostrsigner.models.TimeUtils
import com.greenart7c3.nostrsigner.service.model.Event
@@ -15,10 +17,14 @@ import com.greenart7c3.nostrsigner.ui.theme.NostrSignerTheme
fun EventDataPreview() {
val event = Event("123", "7579076d9aff0a4cfdefa7e2045f2486c7e5d8bc63bfc6b45397233e1bbfcb19", TimeUtils.now(), 1, listOf(), "This is a test 123 123 123 123 123 123", "")
val data = event.toJson()
val remember = remember { mutableStateOf(false) }
NostrSignerTheme(darkTheme = true) {
Scaffold {
EventData(
false,
remember,
null,
"App",
event,
data,