diff --git a/app/build.gradle b/app/build.gradle index 4a8d1f76..76f8ba14 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -75,7 +75,7 @@ dependencies { implementation "androidx.core:core-splashscreen:1.0.1" implementation "androidx.core:core-ktx:$core_ktx_version" - implementation 'androidx.activity:activity-compose:1.8.0' + implementation 'androidx.activity:activity-compose:1.8.1' implementation "androidx.compose.ui:ui:$compose_ui_version" implementation "androidx.compose.ui:ui-tooling-preview:$compose_ui_version" diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/MainActivity.kt b/app/src/main/java/com/greenart7c3/nostrsigner/MainActivity.kt index 64f44f6a..600943d4 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/MainActivity.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/MainActivity.kt @@ -1,5 +1,6 @@ package com.greenart7c3.nostrsigner +import android.content.Intent import android.os.Bundle import androidx.activity.compose.setContent import androidx.appcompat.app.AppCompatActivity @@ -9,12 +10,24 @@ import androidx.compose.material3.Surface import androidx.compose.ui.Modifier import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.WindowCompat +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel import androidx.lifecycle.viewmodel.compose.viewModel +import com.greenart7c3.nostrsigner.models.IntentData +import com.greenart7c3.nostrsigner.service.IntentUtils import com.greenart7c3.nostrsigner.ui.AccountScreen import com.greenart7c3.nostrsigner.ui.AccountStateViewModel import com.greenart7c3.nostrsigner.ui.theme.NostrSignerTheme +class MainViewModel : ViewModel() { + var intents = IntentLiveData() +} + +class IntentLiveData : MutableLiveData>(mutableListOf()) + class MainActivity : AppCompatActivity() { + private val mainViewModel = MainViewModel() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) WindowCompat.setDecorFitsSystemWindows(window, false) @@ -37,9 +50,23 @@ class MainActivity : AppCompatActivity() { val accountStateViewModel: AccountStateViewModel = viewModel { AccountStateViewModel(intent.getStringExtra("current_user")) } - AccountScreen(accountStateViewModel, intent, packageName, appName) + AccountScreen(accountStateViewModel, intent, packageName, appName, mainViewModel) } } } } + + override fun onNewIntent(intent: Intent?) { + super.onNewIntent(intent) + if (intent == null) return + + val list = mutableListOf(IntentUtils.getIntentData(intent)) + mainViewModel.intents.value?.forEach { + if (list.none { item -> item?.id == it?.id }) { + list.add(it) + } + } + + mainViewModel.intents.value = list + } } diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/models/IntentData.kt b/app/src/main/java/com/greenart7c3/nostrsigner/models/IntentData.kt index 2321ea38..b42ccfed 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/models/IntentData.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/models/IntentData.kt @@ -1,5 +1,6 @@ package com.greenart7c3.nostrsigner.models +import androidx.compose.runtime.MutableState import com.vitorpamplona.quartz.encoders.HexKey data class Permission( @@ -44,7 +45,10 @@ class IntentData( val callBackUrl: String?, val compression: CompressionType, val returnType: ReturnType, - val permissions: List? + val permissions: List?, + val currentAccount: String, + val checked: MutableState, + val rememberMyChoice: MutableState ) enum class SignerType { diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt b/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt index 6df2fb83..049f847d 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt @@ -2,6 +2,7 @@ package com.greenart7c3.nostrsigner.service import android.content.Intent import android.net.Uri +import androidx.compose.runtime.mutableStateOf import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.greenart7c3.nostrsigner.models.CompressionType @@ -60,7 +61,10 @@ object IntentUtils { intent.extras?.getString("callbackUrl"), compressionType, returnType, - permissions + permissions, + intent.extras?.getString("current_user") ?: "", + mutableStateOf(true), + mutableStateOf(false) ) } return null diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/AccountScreen.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/AccountScreen.kt index f9b090dc..feeda23a 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/AccountScreen.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/AccountScreen.kt @@ -7,6 +7,8 @@ import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import com.greenart7c3.nostrsigner.MainViewModel import com.greenart7c3.nostrsigner.service.IntentUtils @Composable @@ -14,9 +16,11 @@ fun AccountScreen( accountStateViewModel: AccountStateViewModel, intent: Intent, packageName: String?, - appName: String? + appName: String?, + mainViewModel: MainViewModel ) { val accountState by accountStateViewModel.accountContent.collectAsState() + val intents by mainViewModel.intents.observeAsState() Column { Crossfade( @@ -29,9 +33,12 @@ fun AccountScreen( LoginPage(accountStateViewModel) } is AccountState.LoggedIn -> { - val intentData = IntentUtils.getIntentData(intent) + val localIntents = intents?.mapNotNull { it } ?: listOf() + val newIntents = localIntents.ifEmpty { + listOf(IntentUtils.getIntentData(intent)) + } - MainScreen(state.account, accountStateViewModel, intentData, packageName, appName, state.route) + MainScreen(state.account, accountStateViewModel, newIntents, packageName, appName, state.route) } } } diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/HomeScreen.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/HomeScreen.kt index 9a02d642..cd7ce8b7 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/HomeScreen.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/HomeScreen.kt @@ -1,20 +1,48 @@ package com.greenart7c3.nostrsigner.ui +import android.app.Activity +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 +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.KeyboardArrowDown +import androidx.compose.material.icons.filled.KeyboardArrowUp +import androidx.compose.material3.Button +import androidx.compose.material3.Card +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Icon +import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.google.gson.GsonBuilder +import com.greenart7c3.nostrsigner.LocalPreferences import com.greenart7c3.nostrsigner.R import com.greenart7c3.nostrsigner.models.Account import com.greenart7c3.nostrsigner.models.IntentData @@ -22,9 +50,12 @@ import com.greenart7c3.nostrsigner.models.SignerType import com.greenart7c3.nostrsigner.service.AmberUtils import com.greenart7c3.nostrsigner.service.IntentUtils import com.greenart7c3.nostrsigner.service.getAppCompatActivity +import com.greenart7c3.nostrsigner.service.toShortenHex import com.greenart7c3.nostrsigner.ui.components.EncryptDecryptData import com.greenart7c3.nostrsigner.ui.components.EventData import com.greenart7c3.nostrsigner.ui.components.LoginWithPubKey +import com.greenart7c3.nostrsigner.ui.components.RememberMyChoice +import com.greenart7c3.nostrsigner.ui.theme.ButtonBorder import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.encoders.toNpub import com.vitorpamplona.quartz.events.Event @@ -35,7 +66,7 @@ import kotlinx.coroutines.launch @Composable fun HomeScreen( modifier: Modifier, - json: IntentData?, + intents: List, packageName: String?, applicationName: String?, account: Account @@ -43,110 +74,224 @@ fun HomeScreen( val coroutineScope = rememberCoroutineScope() val context = LocalContext.current val clipboardManager = LocalClipboardManager.current + var loading by remember { mutableStateOf(false) } - Box( - modifier - ) { - if (json == null) { + if (loading) { + Box( + modifier + ) { Column( Modifier.fillMaxSize(), Arrangement.Center, Alignment.CenterHorizontally ) { - Text(stringResource(R.string.no_event_to_sign)) + CircularProgressIndicator() } - } else { - json.let { - var key = "$packageName-${it.type}" - val appName = packageName ?: it.name - when (it.type) { - SignerType.GET_PUBLIC_KEY -> { - val remember = remember { - mutableStateOf(account.savedApps[key] ?: false) - } - LoginWithPubKey( - appName, - applicationName, - json.permissions, - { permissions -> - val sig = account.keyPair.pubKey.toNpub() - coroutineScope.launch { - sendResult( - context, - packageName, - account, - key, - remember.value, - clipboardManager, - sig, - sig, - it, - permissions = permissions - ) + } + } else { + Box( + modifier + ) { + if (intents.filterNotNull().isEmpty()) { + Column( + Modifier.fillMaxSize(), + Arrangement.Center, + Alignment.CenterHorizontally + ) { + Text(stringResource(R.string.no_event_to_sign)) + } + } else { + if (intents.size == 1) { + intents.first()?.let { + var key = "$packageName-${it.type}" + val appName = packageName ?: it.name + when (it.type) { + SignerType.GET_PUBLIC_KEY -> { + val remember = remember { + mutableStateOf(account.savedApps[key] ?: false) } - return@LoginWithPubKey - }, - { - context.getAppCompatActivity()?.finish() - } - ) - } - - SignerType.NIP04_DECRYPT, SignerType.NIP04_ENCRYPT, SignerType.NIP44_ENCRYPT, SignerType.NIP44_DECRYPT, SignerType.DECRYPT_ZAP_EVENT -> { - val remember = remember { - mutableStateOf(account.savedApps[key] ?: false) - } - val shouldRunOnAccept = account.savedApps[key] ?: false - EncryptDecryptData( - it.data, - shouldRunOnAccept, - remember, - packageName, - applicationName, - appName, - it.type, - { - if (it.type == SignerType.NIP04_ENCRYPT && it.data.contains("?iv=", ignoreCase = true)) { - coroutineScope.launch { - Toast.makeText( - context, - context.getString(R.string.message_already_encrypted), - Toast.LENGTH_SHORT - ).show() + LoginWithPubKey( + appName, + applicationName, + it.permissions, + { permissions -> + val sig = account.keyPair.pubKey.toNpub() + coroutineScope.launch { + sendResult( + context, + packageName, + account, + key, + remember.value, + clipboardManager, + sig, + sig, + it, + permissions = permissions + ) + } + return@LoginWithPubKey + }, + { + context.getAppCompatActivity()?.finish() } - return@EncryptDecryptData - } else { - try { - coroutineScope.launch(Dispatchers.IO) { - val sig = try { - AmberUtils.encryptOrDecryptData( - it.data, - it.type, - account, - it.pubKey - ) - ?: "Could not decrypt the message" - } catch (e: Exception) { - "Could not decrypt the message" - } + ) + } + + SignerType.NIP04_DECRYPT, SignerType.NIP04_ENCRYPT, SignerType.NIP44_ENCRYPT, SignerType.NIP44_DECRYPT, SignerType.DECRYPT_ZAP_EVENT -> { + val remember = remember { + mutableStateOf(account.savedApps[key] ?: false) + } + val shouldRunOnAccept = account.savedApps[key] ?: false + EncryptDecryptData( + it.data, + shouldRunOnAccept, + remember, + packageName, + applicationName, + appName, + it.type, + { + if (it.type == SignerType.NIP04_ENCRYPT && it.data.contains( + "?iv=", + ignoreCase = true + ) + ) { + coroutineScope.launch { + Toast.makeText( + context, + context.getString(R.string.message_already_encrypted), + Toast.LENGTH_SHORT + ).show() + } + return@EncryptDecryptData + } else { + try { + coroutineScope.launch(Dispatchers.IO) { + val sig = try { + AmberUtils.encryptOrDecryptData( + it.data, + it.type, + account, + it.pubKey + ) + ?: "Could not decrypt the message" + } catch (e: Exception) { + "Could not decrypt the message" + } + + if (it.type == SignerType.NIP04_ENCRYPT && sig == "Could not decrypt the message") { + coroutineScope.launch { + Toast.makeText( + context, + "Error encrypting content", + Toast.LENGTH_SHORT + ).show() + } + return@launch + } else { + val result = + if (sig == "Could not decrypt the message" && (it.type == SignerType.DECRYPT_ZAP_EVENT)) { + "" + } else { + sig + } + + sendResult( + context, + packageName, + account, + key, + remember.value, + clipboardManager, + result, + result, + it + ) + } + } + + return@EncryptDecryptData + } catch (e: Exception) { + val message = if (it.type.toString().contains("ENCRYPT", true)) { + context.getString(R.string.encrypt) + } else { + context.getString(R.string.decrypt) + } - if (it.type == SignerType.NIP04_ENCRYPT && sig == "Could not decrypt the message") { coroutineScope.launch { Toast.makeText( context, - "Error encrypting content", + context.getString( + R.string.error_to_data, + message + ), Toast.LENGTH_SHORT ).show() } - return@launch - } else { - val result = - if (sig == "Could not decrypt the message" && (it.type == SignerType.DECRYPT_ZAP_EVENT)) { - "" - } else { - sig - } + return@EncryptDecryptData + } + } + }, + { + context.getAppCompatActivity()?.finish() + }, + { + try { + AmberUtils.encryptOrDecryptData( + it.data, + it.type, + account, + it.pubKey + ) + ?: "Could not decrypt the message" + } catch (e: Exception) { + "Could not decrypt the message" + } + } + ) + } + else -> { + val event = IntentUtils.getIntent(it.data, account.keyPair) + key = "$packageName-${it.type}-${event.kind}" + val remember = remember { + mutableStateOf(account.savedApps[key] ?: false) + } + val shouldRunOnAccept = account.savedApps[key] ?: false + EventData( + shouldRunOnAccept, + remember, + packageName, + appName, + applicationName, + event, + it.data, + { + if (event.pubKey != account.keyPair.pubKey.toHexKey()) { + coroutineScope.launch { + Toast.makeText( + context, + context.getString(R.string.event_pubkey_is_not_equal_to_current_logged_in_user), + Toast.LENGTH_SHORT + ).show() + } + return@EventData + } + + val localEvent = try { + Event.fromJson(it.data) + } catch (e: Exception) { + Event.fromJson(event.toJson()) + } + + account.signer.sign( + localEvent.createdAt, + localEvent.kind, + localEvent.tags, + localEvent.content + ) { signedEvent -> + coroutineScope.launch { sendResult( context, packageName, @@ -154,107 +299,294 @@ fun HomeScreen( key, remember.value, clipboardManager, - result, - result, + signedEvent.toJson(), + if (localEvent is LnZapRequestEvent && localEvent.tags.any { tag -> tag.any { t -> t == "anon" } }) signedEvent.toJson() else signedEvent.sig, it ) } } - - return@EncryptDecryptData - } catch (e: Exception) { - val message = - if (it.type.toString().contains("ENCRYPT", true)) { - context.getString(R.string.encrypt) - } else { - context.getString(R.string.decrypt) - } - coroutineScope.launch { - Toast.makeText( - context, - context.getString(R.string.error_to_data, message), - Toast.LENGTH_SHORT - ).show() - } - return@EncryptDecryptData + }, + { + context.getAppCompatActivity()?.finish() } - } - }, - { - context.getAppCompatActivity()?.finish() - }, - { - try { - AmberUtils.encryptOrDecryptData( - it.data, - it.type, - account, - it.pubKey - ) - ?: "Could not decrypt the message" - } catch (e: Exception) { - "Could not decrypt the message" - } + ) } - ) - } - - else -> { - val event = IntentUtils.getIntent(it.data, account.keyPair) - key = "$packageName-${it.type}-${event.kind}" - val remember = remember { - mutableStateOf(account.savedApps[key] ?: false) } - val shouldRunOnAccept = account.savedApps[key] ?: false - EventData( - shouldRunOnAccept, - remember, - packageName, - appName, - applicationName, - event, - it.data, - { - if (event.pubKey != account.keyPair.pubKey.toHexKey()) { - coroutineScope.launch { - Toast.makeText( - context, - context.getString(R.string.event_pubkey_is_not_equal_to_current_logged_in_user), - Toast.LENGTH_SHORT - ).show() + } + } else { + Column( + Modifier.fillMaxSize() + ) { + var selectAll by remember { + mutableStateOf(false) + } + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .padding(horizontal = 8.dp) + .clickable { + selectAll = !selectAll + intents + .filterNotNull() + .forEach { + it.checked.value = selectAll + } + } + ) { + Text( + modifier = Modifier.weight(1f), + text = stringResource(R.string.select_deselect_all) + ) + Switch( + checked = selectAll, + onCheckedChange = { + selectAll = !selectAll + intents.filterNotNull().forEach { + it.checked.value = selectAll } - return@EventData } - - val localEvent = try { - Event.fromJson(it.data) - } catch (e: Exception) { - Event.fromJson(event.toJson()) - } - - account.signer.sign(localEvent.createdAt, localEvent.kind, localEvent.tags, localEvent.content) { signedEvent -> - coroutineScope.launch { - sendResult( - context, - packageName, - account, - key, - remember.value, - clipboardManager, - signedEvent.toJson(), - if (localEvent is LnZapRequestEvent && localEvent.tags.any { tag -> tag.any { t -> t == "anon" } }) signedEvent.toJson() else signedEvent.sig, - it + ) + } + LazyColumn( + Modifier.fillMaxHeight(0.9f) + ) { + items(intents.size) { + var isExpanded by remember { mutableStateOf(false) } + Card( + Modifier + .padding(4.dp) + .clickable { + isExpanded = !isExpanded + } + ) { + intents[it]?.let { + val name = LocalPreferences.getAccountName(it.currentAccount) + Row( + Modifier + .fillMaxWidth(), + Arrangement.Center, + Alignment.CenterVertically + ) { + Text( + name.ifBlank { it.currentAccount.toShortenHex() } + ) + } + } + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .padding(4.dp) + ) { + Icon( + Icons.Default.run { + if (isExpanded) { + KeyboardArrowDown + } else { + KeyboardArrowUp + } + }, + contentDescription = "", + tint = Color.LightGray ) + + intents[it]?.let { + val appName = applicationName ?: packageName ?: it.name + val text = if (it.type == SignerType.SIGN_EVENT) { + val event = + IntentUtils.getIntent(it.data, account.keyPair) + if (event.kind == 22242) "requests client authentication" else "requests event signature" + } else { + when (it.type) { + SignerType.NIP44_ENCRYPT -> stringResource(R.string.encrypt_nip44) + SignerType.NIP04_ENCRYPT -> stringResource(R.string.encrypt_nip04) + SignerType.NIP44_DECRYPT -> stringResource(R.string.decrypt_nip44) + SignerType.NIP04_DECRYPT -> stringResource(R.string.decrypt_nip04) + SignerType.DECRYPT_ZAP_EVENT -> stringResource(R.string.decrypt_zap_event) + else -> stringResource(R.string.encrypt_decrypt) + } + } + Text( + modifier = Modifier.weight(1f), + text = buildAnnotatedString { + withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) { + append(appName) + } + append(" $text") + }, + fontSize = 18.sp + ) + + Switch( + checked = it.checked.value, + onCheckedChange = { _ -> + it.checked.value = !it.checked.value + } + ) + } + } + intents[it]?.let { + if (isExpanded) { + Column( + Modifier + .fillMaxSize() + .padding(10.dp) + ) { + Text( + "Event content", + fontWeight = FontWeight.Bold + ) + val content = + if (it.type == SignerType.SIGN_EVENT) { + val event = IntentUtils.getIntent( + it.data, + account.keyPair + ) + if (event.kind == 22242) event.relay() else event.content + } else { + it.data + } + Text( + content, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp) + ) + RememberMyChoice( + shouldRunOnAccept = false, + it.rememberMyChoice.value, + packageName, + { } + ) { + it.rememberMyChoice.value = !it.rememberMyChoice.value + intents.filter { intentData -> + intentData?.type == it.type + }.forEach { intentData -> + intentData?.let { intent -> + intent.rememberMyChoice.value = + it.rememberMyChoice.value + } + } + } + } + } } } - }, - { - context.getAppCompatActivity()?.finish() } - ) + } + Row( + Modifier + .fillMaxWidth() + .padding(10.dp), + Arrangement.Center + ) { + Button( + modifier = Modifier.fillMaxWidth(), + shape = ButtonBorder, + onClick = { + loading = true + coroutineScope.launch(Dispatchers.IO) { + try { + val activity = context.getAppCompatActivity() + val results = mutableListOf() + + for (intentData in intents.filterNotNull()) { + val localAccount = + if (intentData.currentAccount.isNotBlank()) { + LocalPreferences.loadFromEncryptedStorage( + intentData.currentAccount + ) + } else { + account + } ?: continue + + if (packageName != null) { + if (intentData.type == SignerType.SIGN_EVENT) { + val localEvent = try { + Event.fromJson(intentData.data) + } catch (e: Exception) { + Event.fromJson( + IntentUtils.getIntent( + intentData.data, + localAccount.keyPair + ).toJson() + ) + } + val key = "$packageName-${intentData.type}-${localEvent.kind}" + if (intentData.rememberMyChoice.value) { + localAccount.savedApps[key] = + intentData.rememberMyChoice.value + LocalPreferences.saveToEncryptedStorage( + localAccount + ) + } + localAccount.signer.sign( + localEvent.createdAt, + localEvent.kind, + localEvent.tags, + localEvent.content + ) { signedEvent -> + results.add( + Result( + null, + signedEvent.sig, + intentData.id + ) + ) + } + } else { + val key = "$packageName-${intentData.type}" + localAccount.savedApps[key] = + intentData.rememberMyChoice.value + LocalPreferences.saveToEncryptedStorage( + localAccount + ) + val signature = AmberUtils.encryptOrDecryptData( + intentData.data, + intentData.type, + localAccount, + intentData.pubKey + ) ?: continue + results.add( + Result( + null, + signature, + intentData.id + ) + ) + } + } + } + + if (results.isNotEmpty()) { + val gson = GsonBuilder().serializeNulls().create() + val json = gson.toJson(results) + val intent = Intent() + intent.putExtra("results", json) + activity?.setResult(Activity.RESULT_OK, intent) + } + activity?.finish() + } finally { + loading = false + } + } + } + ) { + Text("Confirm") + } + } } } } } } } + +class Result( + val `package`: String?, + val signature: String?, + val id: String? +) diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/MainScreen.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/MainScreen.kt index 3375af3e..9a377915 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/MainScreen.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/MainScreen.kt @@ -175,7 +175,7 @@ fun GoToTop(goToTop: () -> Unit) { fun MainScreen( account: Account, accountStateViewModel: AccountStateViewModel, - json: IntentData?, + intents: List, packageName: String?, appName: String?, route: String? @@ -291,7 +291,7 @@ fun MainScreen( Modifier .fillMaxSize() .padding(padding), - json, + intents, packageName, appName, account diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EncryptDecryptData.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EncryptDecryptData.kt index 601bc8cf..29744332 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EncryptDecryptData.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EncryptDecryptData.kt @@ -122,10 +122,12 @@ fun EncryptDecryptData( RememberMyChoice( shouldRunOnAccept, - remember, + remember.value, packageName, onAccept - ) + ) { + remember.value = !remember.value + } AcceptRejectButtons( onAccept, diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EventData.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EventData.kt index 859d18d8..8496577a 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EventData.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EventData.kt @@ -91,10 +91,12 @@ fun EventData( RememberMyChoice( shouldRunOnAccept, - remember, + remember.value, packageName, onAccept - ) + ) { + remember.value = !remember.value + } AcceptRejectButtons( onAccept, diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/RememberMyChoice.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/RememberMyChoice.kt index 4e2802e0..e325ea9c 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/RememberMyChoice.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/RememberMyChoice.kt @@ -7,7 +7,6 @@ import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.MutableState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -16,9 +15,10 @@ import com.greenart7c3.nostrsigner.R @Composable fun RememberMyChoice( shouldRunOnAccept: Boolean, - remember: MutableState, + remember: Boolean, packageName: String?, - onAccept: () -> Unit + onAccept: () -> Unit, + onChanged: () -> Unit ) { if (shouldRunOnAccept) { LaunchedEffect(Unit) { @@ -31,7 +31,7 @@ fun RememberMyChoice( verticalAlignment = Alignment.CenterVertically, modifier = Modifier .clickable { - remember.value = !remember.value + onChanged() } ) { Text( @@ -39,9 +39,9 @@ fun RememberMyChoice( text = stringResource(R.string.remember_my_choice_and_don_t_ask_again) ) Switch( - checked = remember.value, + checked = remember, onCheckedChange = { - remember.value = !remember.value + onChanged() } ) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a04bd2a3..8ca4ebb4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -81,4 +81,5 @@ Relay go to top Event copied to the clipboard + Select/Deselect all \ No newline at end of file