mirror of
https://github.com/greenart7c3/Amber.git
synced 2026-10-05 19:08:23 +00:00
add remember my choice switch
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user