mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-11-10 22:36:49 +01:00
Merge pull request #1493 from greenart7c3/main
Show a dialog to select a signer when using multiple signers
This commit is contained in:
@@ -23,12 +23,39 @@ package com.vitorpamplona.amethyst.ui.screen.loggedOff.login
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
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.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.input.TextFieldValue
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
|
import coil3.compose.rememberAsyncImagePainter
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.DefaultSignerPermissions
|
import com.vitorpamplona.amethyst.model.DefaultSignerPermissions
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size0dp
|
import com.vitorpamplona.amethyst.ui.theme.Size0dp
|
||||||
@@ -37,6 +64,7 @@ import com.vitorpamplona.amethyst.ui.theme.Size40dp
|
|||||||
import com.vitorpamplona.quartz.nip55AndroidSigner.api.PubKeyResult
|
import com.vitorpamplona.quartz.nip55AndroidSigner.api.PubKeyResult
|
||||||
import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult
|
import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult
|
||||||
import com.vitorpamplona.quartz.nip55AndroidSigner.client.ExternalSignerLogin
|
import com.vitorpamplona.quartz.nip55AndroidSigner.client.ExternalSignerLogin
|
||||||
|
import com.vitorpamplona.quartz.nip55AndroidSigner.client.getExternalSignersInstalled
|
||||||
import com.vitorpamplona.quartz.utils.Log
|
import com.vitorpamplona.quartz.utils.Log
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -44,6 +72,9 @@ import kotlinx.coroutines.launch
|
|||||||
@Composable
|
@Composable
|
||||||
fun ExternalSignerButton(loginViewModel: LoginViewModel) {
|
fun ExternalSignerButton(loginViewModel: LoginViewModel) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
val context = LocalContext.current
|
||||||
|
val installedSigners = getExternalSignersInstalled(context)
|
||||||
|
var shouldSelectSigner by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val launcher =
|
val launcher =
|
||||||
rememberLauncherForActivityResult(
|
rememberLauncherForActivityResult(
|
||||||
@@ -63,6 +94,81 @@ fun ExternalSignerButton(loginViewModel: LoginViewModel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shouldSelectSigner) {
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = {
|
||||||
|
shouldSelectSigner = false
|
||||||
|
},
|
||||||
|
content = {
|
||||||
|
Surface(
|
||||||
|
shape = RoundedCornerShape(4.dp),
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.padding(8.dp),
|
||||||
|
text = stringResource(R.string.select_signer),
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 24.sp,
|
||||||
|
)
|
||||||
|
Spacer(Modifier.height(4.dp))
|
||||||
|
LazyColumn {
|
||||||
|
items(installedSigners) {
|
||||||
|
val appName = it.loadLabel(context.packageManager).toString()
|
||||||
|
val appIcon = it.loadIcon(context.packageManager)
|
||||||
|
val iconBitmap = appIcon.toBitmap()
|
||||||
|
|
||||||
|
Row(
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(start = 16.dp, end = 16.dp, bottom = 8.dp, top = 8.dp)
|
||||||
|
.clickable {
|
||||||
|
if (!loginViewModel.acceptedTerms) {
|
||||||
|
loginViewModel.termsAcceptanceIsRequiredError = true
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
launcher.launch(ExternalSignerLogin.createIntent(DefaultSignerPermissions, it.activityInfo.packageName))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (e is CancellationException) throw e
|
||||||
|
Log.e("ExternalSigner", "Error opening Signer app", e)
|
||||||
|
loginViewModel.errorManager.error(R.string.error_opening_external_signer)
|
||||||
|
} finally {
|
||||||
|
shouldSelectSigner = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
val painter =
|
||||||
|
rememberAsyncImagePainter(
|
||||||
|
iconBitmap,
|
||||||
|
)
|
||||||
|
|
||||||
|
Image(
|
||||||
|
painter = painter,
|
||||||
|
contentDescription = appName,
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
.padding(end = 16.dp),
|
||||||
|
)
|
||||||
|
Column {
|
||||||
|
Text(appName)
|
||||||
|
Text(
|
||||||
|
it.activityInfo.packageName,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = Color.Gray,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Box(modifier = Modifier.padding(Size40dp, Size20dp, Size40dp, Size0dp)) {
|
Box(modifier = Modifier.padding(Size40dp, Size20dp, Size40dp, Size0dp)) {
|
||||||
LoginWithAmberButton(
|
LoginWithAmberButton(
|
||||||
enabled = loginViewModel.acceptedTerms,
|
enabled = loginViewModel.acceptedTerms,
|
||||||
@@ -71,7 +177,11 @@ fun ExternalSignerButton(loginViewModel: LoginViewModel) {
|
|||||||
loginViewModel.termsAcceptanceIsRequiredError = true
|
loginViewModel.termsAcceptanceIsRequiredError = true
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
if (installedSigners.size == 1) {
|
||||||
launcher.launch(ExternalSignerLogin.createIntent(DefaultSignerPermissions))
|
launcher.launch(ExternalSignerLogin.createIntent(DefaultSignerPermissions))
|
||||||
|
} else {
|
||||||
|
shouldSelectSigner = true
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
if (e is CancellationException) throw e
|
if (e is CancellationException) throw e
|
||||||
Log.e("ExternalSigner", "Error opening Signer app", e)
|
Log.e("ExternalSigner", "Error opening Signer app", e)
|
||||||
|
|||||||
@@ -1289,4 +1289,5 @@
|
|||||||
<string name="would_you_like_to_send_the_recent_crash_report_to_amethyst_in_a_dm_no_personal_information_will_be_shared">Would you like to send the recent crash report to Amethyst in a DM? No personal information will be shared</string>
|
<string name="would_you_like_to_send_the_recent_crash_report_to_amethyst_in_a_dm_no_personal_information_will_be_shared">Would you like to send the recent crash report to Amethyst in a DM? No personal information will be shared</string>
|
||||||
<string name="crashreport_found_send">Send it</string>
|
<string name="crashreport_found_send">Send it</string>
|
||||||
<string name="this_message_will_disappear_in_days">This message will disappear in %1$d days</string>
|
<string name="this_message_will_disappear_in_days">This message will disappear in %1$d days</string>
|
||||||
|
<string name="select_signer">Select Signer</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -29,9 +29,15 @@ import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.result
|
|||||||
import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.Permission
|
import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.Permission
|
||||||
|
|
||||||
object ExternalSignerLogin {
|
object ExternalSignerLogin {
|
||||||
fun createIntent(permissions: List<Permission> = LoginRequest.DefaultPermissions): Intent {
|
fun createIntent(
|
||||||
|
permissions: List<Permission> = LoginRequest.DefaultPermissions,
|
||||||
|
packageName: String = "",
|
||||||
|
): Intent {
|
||||||
val intent = LoginRequest.assemble(permissions)
|
val intent = LoginRequest.assemble(permissions)
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
|
if (packageName.isNotBlank()) {
|
||||||
|
intent.`package` = packageName
|
||||||
|
}
|
||||||
return intent
|
return intent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ package com.vitorpamplona.quartz.nip55AndroidSigner.client
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.pm.ResolveInfo
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
|
|
||||||
@SuppressLint("QueryPermissionsNeeded")
|
@SuppressLint("QueryPermissionsNeeded")
|
||||||
@@ -35,3 +36,14 @@ fun isExternalSignerInstalled(context: Context): Boolean =
|
|||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
).isNotEmpty()
|
).isNotEmpty()
|
||||||
|
|
||||||
|
@SuppressLint("QueryPermissionsNeeded")
|
||||||
|
fun getExternalSignersInstalled(context: Context): List<ResolveInfo> =
|
||||||
|
context.packageManager
|
||||||
|
.queryIntentActivities(
|
||||||
|
Intent().apply {
|
||||||
|
action = Intent.ACTION_VIEW
|
||||||
|
data = "nostrsigner:".toUri()
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user