From c66fa1073bcdf1bd0ffd9084e288ac494c82b5ff Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 8 Oct 2024 16:09:09 -0400 Subject: [PATCH] Fixes intent reopening the Zap Setup screen because it was saved in the backstack of the Home screen. --- .../vitorpamplona/amethyst/ui/MainActivity.kt | 2 +- .../amethyst/ui/navigation/AppNavigation.kt | 40 +- .../amethyst/ui/navigation/Routes.kt | 27 +- .../amethyst/ui/note/UpdateZapAmountDialog.kt | 649 +++++++++--------- .../ui/screen/loggedIn/home/HomeScreen.kt | 17 - .../loggedIn/settings/NIP47SetupScreen.kt | 93 +++ amethyst/src/main/res/values/strings.xml | 1 + 7 files changed, 460 insertions(+), 369 deletions(-) create mode 100644 amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index 76240732d..3c6daa69f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -324,7 +324,7 @@ fun uriToRoute(uri: String?): String? = uri?.let { Nip47WalletConnect.parse(it) val encodedUri = URLEncoder.encode(it, StandardCharsets.UTF_8.toString()) - Route.Home.base + "?nip47=" + encodedUri + Route.NIP47Setup.base + "?nip47=" + encodedUri } } catch (e: Exception) { if (e is CancellationException) throw e diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt index cb83f3698..f0df025ad 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt @@ -67,6 +67,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.HomeScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.NotificationScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.ProfileScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.search.SearchScreen +import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.NIP47SetupScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SecurityFiltersScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.ThreadScreen @@ -100,24 +101,7 @@ fun AppNavigation( enterTransition = { fadeIn(animationSpec = tween(200)) }, exitTransition = { fadeOut(animationSpec = tween(200)) }, ) { - composable( - Route.Home.route, - Route.Home.arguments, - ) { - val nip47 = it.arguments?.getString("nip47") - - HomeScreen(accountViewModel, nav, nip47) - - if (nip47 != null) { - LaunchedEffect(key1 = Unit) { - launch { - delay(1000) - it.arguments?.remove("nip47") - } - } - } - } - + composable(Route.Home.route) { HomeScreen(accountViewModel, nav) } composable(Route.Message.route) { ChatroomListScreen(accountViewModel, nav) } composable(Route.Video.route) { VideoScreen(accountViewModel, nav) } composable(Route.Discover.route) { DiscoverScreen(accountViewModel, nav) } @@ -282,6 +266,21 @@ fun AppNavigation( nav, ) } + + composable( + Route.NIP47Setup.route, + Route.NIP47Setup.arguments, + enterTransition = { slideInHorizontallyFromEnd }, + exitTransition = { scaleOut }, + popEnterTransition = { scaleIn }, + popExitTransition = { slideOutHorizontallyToEnd }, + ) { + val nip47 = it.arguments?.getString("nip47") + + println("AABBCC NavHost Home $nip47") + + NIP47SetupScreen(accountViewModel, nav, nip47) + } } } @@ -297,6 +296,8 @@ private fun NavigateIfIntentRequested( accountViewModel: AccountViewModel, accountStateViewModel: AccountStateViewModel, ) { + println("AABBCC NavigateIfIntentRequested") + val activity = LocalContext.current.getActivity() var newAccount by remember { mutableStateOf(null) } @@ -315,6 +316,7 @@ private fun NavigateIfIntentRequested( } LaunchedEffect(intentNextPage) { + println("AABBCC NavigateIfIntentRequested LaunchedEffect(intentNextPage)") if (actionableNextPage != null) { actionableNextPage?.let { val currentRoute = getRouteWithArguments(nav.controller) @@ -347,6 +349,8 @@ private fun NavigateIfIntentRequested( DisposableEffect(nav, activity) { val consumer = Consumer { intent -> + println("AABBCC NavigateIfIntentRequested DisposableEffect(nav, activity)") + val uri = intent.data?.toString() if (!uri.isNullOrBlank()) { // navigation functions diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt index f30e4195d..6a35447cf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt @@ -52,18 +52,10 @@ sealed class Route( ) { object Home : Route( - route = "Home?nip47={nip47}", + route = "Home", icon = R.drawable.ic_home, notifSize = Modifier.size(Size25dp), iconSize = Modifier.size(Size24dp), - arguments = - listOf( - navArgument("nip47") { - type = NavType.StringType - nullable = true - defaultValue = null - }, - ).toImmutableList(), contentDescriptor = R.string.route_home, ) @@ -92,9 +84,6 @@ sealed class Route( Route( route = "Discover", icon = R.drawable.ic_sensors, - // hasNewItems = { accountViewModel, newNotes -> - // DiscoverLatestItem.hasNewItems(accountViewModel, newNotes) - // }, contentDescriptor = R.string.route_discover, ) @@ -217,6 +206,20 @@ sealed class Route( route = "Settings", icon = R.drawable.ic_settings, ) + + object NIP47Setup : + Route( + route = "NIP47Setup?nip47={nip47}", + icon = R.drawable.ic_home, + arguments = + listOf( + navArgument("nip47") { + type = NavType.StringType + nullable = true + defaultValue = null + }, + ).toImmutableList(), + ) } fun getRouteWithArguments(navController: NavHostController): String? { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt index a36f40f91..0f0414af1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt @@ -31,7 +31,6 @@ import androidx.activity.result.ActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.biometric.BiometricManager import androidx.biometric.BiometricPrompt -import androidx.compose.animation.animateContentSize import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi @@ -220,16 +219,66 @@ fun UpdateZapAmountDialog( onClose: () -> Unit, nip47uri: String? = null, accountViewModel: AccountViewModel, +) { + Dialog( + onDismissRequest = { onClose() }, + properties = + DialogProperties( + usePlatformDefaultWidth = false, + dismissOnClickOutside = false, + decorFitsSystemWindows = false, + ), + ) { + Surface( + modifier = Modifier.fillMaxWidth(), + ) { + Column { + val postViewModel: UpdateZapAmountViewModel = + viewModel( + key = "UpdateZapAmountViewModel", + factory = UpdateZapAmountViewModel.Factory(accountViewModel.account.settings), + ) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + CloseButton( + onPress = { + postViewModel.cancel() + onClose() + }, + ) + + SaveButton( + onPost = { + postViewModel.sendPost() + onClose() + }, + isActive = postViewModel.hasChanged(), + ) + } + + Spacer(modifier = Modifier.height(10.dp)) + + UpdateZapAmountContent(postViewModel, onClose, nip47uri, accountViewModel) + } + } + } +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun UpdateZapAmountContent( + postViewModel: UpdateZapAmountViewModel, + onClose: () -> Unit, + nip47uri: String? = null, + accountViewModel: AccountViewModel, ) { val context = LocalContext.current val clipboardManager = LocalClipboardManager.current - val postViewModel: UpdateZapAmountViewModel = - viewModel( - key = "UpdateZapAmountViewModel", - factory = UpdateZapAmountViewModel.Factory(accountViewModel.account.settings), - ) - val uri = LocalUriHandler.current val zapTypes = @@ -282,337 +331,295 @@ fun UpdateZapAmountDialog( } } - Dialog( - onDismissRequest = { onClose() }, - properties = - DialogProperties( - usePlatformDefaultWidth = false, - dismissOnClickOutside = false, - decorFitsSystemWindows = false, - ), + Column( + modifier = + Modifier + .padding(10.dp) + .fillMaxWidth() + .imePadding() + .verticalScroll(rememberScrollState()), ) { - Surface( + FlowRow( modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center, ) { - Column(modifier = Modifier.padding(10.dp).imePadding()) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, + postViewModel.amountSet.forEach { amountInSats -> + Button( + modifier = Modifier.padding(horizontal = 3.dp), + shape = ButtonBorder, + colors = + ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.primary, + ), + onClick = { postViewModel.removeAmount(amountInSats) }, ) { - CloseButton( - onPress = { - postViewModel.cancel() - onClose() - }, - ) - - SaveButton( - onPost = { - postViewModel.sendPost() - onClose() - }, - isActive = postViewModel.hasChanged(), + Text( + "⚡ ${ + showAmount( + amountInSats.toBigDecimal().setScale(1), + ) + } ✖", + color = Color.White, + textAlign = TextAlign.Center, ) } + } + } - Spacer(modifier = Modifier.height(10.dp)) + Spacer(modifier = Modifier.height(10.dp)) - Row( - modifier = Modifier.fillMaxWidth(), - ) { - Column( - modifier = Modifier.verticalScroll(rememberScrollState()), - ) { - Row(modifier = Modifier.fillMaxWidth()) { - Column(modifier = Modifier.animateContentSize()) { - FlowRow( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center, - ) { - postViewModel.amountSet.forEach { amountInSats -> - Button( - modifier = Modifier.padding(horizontal = 3.dp), - shape = ButtonBorder, - colors = - ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.primary, - ), - onClick = { postViewModel.removeAmount(amountInSats) }, - ) { - Text( - "⚡ ${ - showAmount( - amountInSats.toBigDecimal().setScale(1), - ) - } ✖", - color = Color.White, - textAlign = TextAlign.Center, - ) - } - } - } - } - } + Row( + modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + OutlinedTextField( + label = { Text(text = stringRes(R.string.new_amount_in_sats)) }, + value = postViewModel.nextAmount, + onValueChange = { postViewModel.nextAmount = it }, + keyboardOptions = + KeyboardOptions.Default.copy( + capitalization = KeyboardCapitalization.None, + keyboardType = KeyboardType.Number, + ), + placeholder = { + Text( + text = "100, 1000, 5000", + color = MaterialTheme.colorScheme.placeholderText, + ) + }, + singleLine = true, + modifier = Modifier.padding(end = 10.dp).weight(1f), + ) - Spacer(modifier = Modifier.height(10.dp)) + Button( + onClick = { postViewModel.addAmount() }, + shape = ButtonBorder, + colors = + ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.primary, + ), + ) { + Text(text = stringRes(R.string.add), color = Color.White) + } + } - Row( - modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - OutlinedTextField( - label = { Text(text = stringRes(R.string.new_amount_in_sats)) }, - value = postViewModel.nextAmount, - onValueChange = { postViewModel.nextAmount = it }, - keyboardOptions = - KeyboardOptions.Default.copy( - capitalization = KeyboardCapitalization.None, - keyboardType = KeyboardType.Number, - ), - placeholder = { - Text( - text = "100, 1000, 5000", - color = MaterialTheme.colorScheme.placeholderText, - ) - }, - singleLine = true, - modifier = Modifier.padding(end = 10.dp).weight(1f), + Row( + modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + TextSpinner( + label = stringRes(id = R.string.zap_type_explainer), + placeholder = + zapTypes.filter { it.first == accountViewModel.defaultZapType() }.first().second, + options = zapOptions, + onSelect = { postViewModel.selectedZapType = zapTypes[it].first }, + modifier = Modifier.weight(1f).padding(end = 5.dp), + ) + } + + HorizontalDivider( + modifier = Modifier.padding(vertical = 10.dp), + thickness = DividerThickness, + ) + + var qrScanning by remember { mutableStateOf(false) } + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + stringRes(id = R.string.wallet_connect_service), + Modifier.weight(1f), + ) + + IconButton( + onClick = { + onClose() + runCatching { uri.openUri("https://nwc.getalby.com/apps/new?c=Amethyst") } + }, + ) { + Icon( + painter = painterResource(R.drawable.alby), + contentDescription = stringRes(id = R.string.accessibility_navigate_to_alby), + modifier = Modifier.size(24.dp), + tint = Color.Unspecified, + ) + } + + IconButton( + onClick = { + clipboardManager.getText()?.let { postViewModel.copyFromClipboard(it.text) } + }, + ) { + Icon( + Icons.Outlined.ContentPaste, + contentDescription = stringRes(id = R.string.paste_from_clipboard), + modifier = Modifier.size(24.dp), + tint = MaterialTheme.colorScheme.primary, + ) + } + + IconButton(onClick = { qrScanning = true }) { + Icon( + painter = painterResource(R.drawable.ic_qrcode), + contentDescription = stringRes(id = R.string.accessibility_scan_qr_code), + modifier = Modifier.size(24.dp), + tint = MaterialTheme.colorScheme.primary, + ) + } + } + + Row( + modifier = Modifier.fillMaxWidth().padding(bottom = 5.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + stringRes(id = R.string.wallet_connect_service_explainer), + Modifier.weight(1f), + color = MaterialTheme.colorScheme.placeholderText, + fontSize = Font14SP, + ) + } + + if (qrScanning) { + SimpleQrCodeScanner { + qrScanning = false + if (!it.isNullOrEmpty()) { + try { + postViewModel.updateNIP47(it) + } catch (e: IllegalArgumentException) { + if (e.message != null) { + accountViewModel.toast( + stringRes(context, R.string.error_parsing_nip47_title), + stringRes(context, R.string.error_parsing_nip47, it, e.message!!), ) - - Button( - onClick = { postViewModel.addAmount() }, - shape = ButtonBorder, - colors = - ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.primary, - ), - ) { - Text(text = stringRes(R.string.add), color = Color.White) - } - } - - Row( - modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - TextSpinner( - label = stringRes(id = R.string.zap_type_explainer), - placeholder = - zapTypes.filter { it.first == accountViewModel.defaultZapType() }.first().second, - options = zapOptions, - onSelect = { postViewModel.selectedZapType = zapTypes[it].first }, - modifier = Modifier.weight(1f).padding(end = 5.dp), - ) - } - - HorizontalDivider( - modifier = Modifier.padding(vertical = 10.dp), - thickness = DividerThickness, - ) - - var qrScanning by remember { mutableStateOf(false) } - - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - stringRes(id = R.string.wallet_connect_service), - Modifier.weight(1f), - ) - - IconButton( - onClick = { - onClose() - runCatching { uri.openUri("https://nwc.getalby.com/apps/new?c=Amethyst") } - }, - ) { - Icon( - painter = painterResource(R.drawable.alby), - contentDescription = stringRes(id = R.string.accessibility_navigate_to_alby), - modifier = Modifier.size(24.dp), - tint = Color.Unspecified, - ) - } - - IconButton( - onClick = { - clipboardManager.getText()?.let { postViewModel.copyFromClipboard(it.text) } - }, - ) { - Icon( - Icons.Outlined.ContentPaste, - contentDescription = stringRes(id = R.string.paste_from_clipboard), - modifier = Modifier.size(24.dp), - tint = MaterialTheme.colorScheme.primary, - ) - } - - IconButton(onClick = { qrScanning = true }) { - Icon( - painter = painterResource(R.drawable.ic_qrcode), - contentDescription = stringRes(id = R.string.accessibility_scan_qr_code), - modifier = Modifier.size(24.dp), - tint = MaterialTheme.colorScheme.primary, - ) - } - } - - Row( - modifier = Modifier.fillMaxWidth().padding(bottom = 5.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - stringRes(id = R.string.wallet_connect_service_explainer), - Modifier.weight(1f), - color = MaterialTheme.colorScheme.placeholderText, - fontSize = Font14SP, - ) - } - - if (qrScanning) { - SimpleQrCodeScanner { - qrScanning = false - if (!it.isNullOrEmpty()) { - try { - postViewModel.updateNIP47(it) - } catch (e: IllegalArgumentException) { - if (e.message != null) { - accountViewModel.toast( - stringRes(context, R.string.error_parsing_nip47_title), - stringRes(context, R.string.error_parsing_nip47, it, e.message!!), - ) - } else { - accountViewModel.toast( - stringRes(context, R.string.error_parsing_nip47_title), - stringRes(context, R.string.error_parsing_nip47_no_error, it), - ) - } - } - } - } - } - - Row( - modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - OutlinedTextField( - label = { Text(text = stringRes(R.string.wallet_connect_service_pubkey)) }, - value = postViewModel.walletConnectPubkey, - onValueChange = { postViewModel.walletConnectPubkey = it }, - keyboardOptions = - KeyboardOptions.Default.copy( - capitalization = KeyboardCapitalization.None, - ), - placeholder = { - Text( - text = "npub, hex", - color = MaterialTheme.colorScheme.placeholderText, - ) - }, - singleLine = true, - modifier = Modifier.weight(1f), - ) - } - - Row( - modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - OutlinedTextField( - label = { Text(text = stringRes(R.string.wallet_connect_service_relay)) }, - modifier = Modifier.weight(1f), - value = postViewModel.walletConnectRelay, - onValueChange = { postViewModel.walletConnectRelay = it }, - placeholder = { - Text( - text = "wss://relay.server.com", - color = MaterialTheme.colorScheme.placeholderText, - maxLines = 1, - ) - }, - singleLine = true, - ) - } - - var showPassword by remember { mutableStateOf(false) } - - val context = LocalContext.current - - val keyguardLauncher = - rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> - if (result.resultCode == Activity.RESULT_OK) { - showPassword = true - } - } - - val authTitle = stringRes(id = R.string.wallet_connect_service_show_secret) - - Row( - modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - OutlinedTextField( - label = { Text(text = stringRes(R.string.wallet_connect_service_secret)) }, - modifier = Modifier.weight(1f), - value = postViewModel.walletConnectSecret, - onValueChange = { postViewModel.walletConnectSecret = it }, - keyboardOptions = - KeyboardOptions( - autoCorrect = false, - keyboardType = KeyboardType.Password, - imeAction = ImeAction.Go, - ), - placeholder = { - Text( - text = stringRes(R.string.wallet_connect_service_secret_placeholder), - color = MaterialTheme.colorScheme.placeholderText, - ) - }, - trailingIcon = { - IconButton( - onClick = { - if (!showPassword) { - authenticate( - title = authTitle, - context = context, - keyguardLauncher = keyguardLauncher, - onApproved = { showPassword = true }, - onError = { title, message -> accountViewModel.toast(title, message) }, - ) - } else { - showPassword = false - } - }, - ) { - Icon( - imageVector = - if (showPassword) { - Icons.Outlined.VisibilityOff - } else { - Icons.Outlined.Visibility - }, - contentDescription = - if (showPassword) { - stringRes(R.string.show_password) - } else { - stringRes( - R.string.hide_password, - ) - }, - ) - } - }, - visualTransformation = - if (showPassword) VisualTransformation.None else PasswordVisualTransformation(), + } else { + accountViewModel.toast( + stringRes(context, R.string.error_parsing_nip47_title), + stringRes(context, R.string.error_parsing_nip47_no_error, it), ) } } } } } + + Row( + modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + OutlinedTextField( + label = { Text(text = stringRes(R.string.wallet_connect_service_pubkey)) }, + value = postViewModel.walletConnectPubkey, + onValueChange = { postViewModel.walletConnectPubkey = it }, + keyboardOptions = + KeyboardOptions.Default.copy( + capitalization = KeyboardCapitalization.None, + ), + placeholder = { + Text( + text = "npub, hex", + color = MaterialTheme.colorScheme.placeholderText, + ) + }, + singleLine = true, + modifier = Modifier.weight(1f), + ) + } + + Row( + modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + OutlinedTextField( + label = { Text(text = stringRes(R.string.wallet_connect_service_relay)) }, + modifier = Modifier.weight(1f), + value = postViewModel.walletConnectRelay, + onValueChange = { postViewModel.walletConnectRelay = it }, + placeholder = { + Text( + text = "wss://relay.server.com", + color = MaterialTheme.colorScheme.placeholderText, + maxLines = 1, + ) + }, + singleLine = true, + ) + } + + var showPassword by remember { mutableStateOf(false) } + + val context = LocalContext.current + + val keyguardLauncher = + rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> + if (result.resultCode == Activity.RESULT_OK) { + showPassword = true + } + } + + val authTitle = stringRes(id = R.string.wallet_connect_service_show_secret) + + Row( + modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + OutlinedTextField( + label = { Text(text = stringRes(R.string.wallet_connect_service_secret)) }, + modifier = Modifier.weight(1f), + value = postViewModel.walletConnectSecret, + onValueChange = { postViewModel.walletConnectSecret = it }, + keyboardOptions = + KeyboardOptions( + autoCorrect = false, + keyboardType = KeyboardType.Password, + imeAction = ImeAction.Go, + ), + placeholder = { + Text( + text = stringRes(R.string.wallet_connect_service_secret_placeholder), + color = MaterialTheme.colorScheme.placeholderText, + ) + }, + trailingIcon = { + IconButton( + onClick = { + if (!showPassword) { + authenticate( + title = authTitle, + context = context, + keyguardLauncher = keyguardLauncher, + onApproved = { showPassword = true }, + onError = { title, message -> accountViewModel.toast(title, message) }, + ) + } else { + showPassword = false + } + }, + ) { + Icon( + imageVector = + if (showPassword) { + Icons.Outlined.VisibilityOff + } else { + Icons.Outlined.Visibility + }, + contentDescription = + if (showPassword) { + stringRes(R.string.show_password) + } else { + stringRes( + R.string.hide_password, + ) + }, + ) + } + }, + visualTransformation = + if (showPassword) VisualTransformation.None else PasswordVisualTransformation(), + ) + } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeScreen.kt index 4b3d98539..94af2c47b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeScreen.kt @@ -63,7 +63,6 @@ import com.vitorpamplona.amethyst.ui.feeds.rememberForeverPagerState import com.vitorpamplona.amethyst.ui.navigation.AppBottomBar import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.navigation.Route -import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.DisappearingScaffold import com.vitorpamplona.amethyst.ui.stringRes @@ -78,10 +77,7 @@ import kotlinx.coroutines.launch fun HomeScreen( accountViewModel: AccountViewModel, nav: INav, - nip47: String? = null, ) { - ResolveNIP47(nip47, accountViewModel) - HomeScreen( newThreadsFeedState = accountViewModel.feedStates.homeNewThreads, repliesFeedState = accountViewModel.feedStates.homeReplies, @@ -139,18 +135,6 @@ private fun AssembleHomeTabs( inner(pagerState, tabs) } -@Composable -fun ResolveNIP47( - nip47: String?, - accountViewModel: AccountViewModel, -) { - var wantsToAddNip47 by remember(nip47) { mutableStateOf(nip47) } - - if (wantsToAddNip47 != null) { - UpdateZapAmountDialog({ wantsToAddNip47 = null }, wantsToAddNip47, accountViewModel) - } -} - @Composable private fun WatchLifeCycleChanges(accountViewModel: AccountViewModel) { val lifeCycleOwner = LocalLifecycleOwner.current @@ -169,7 +153,6 @@ private fun WatchLifeCycleChanges(accountViewModel: AccountViewModel) { } @Composable -@OptIn(ExperimentalFoundationApi::class) private fun HomePages( pagerState: PagerState, tabs: ImmutableList, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt new file mode 100644 index 000000000..605881139 --- /dev/null +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.IconButton +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.lifecycle.viewmodel.compose.viewModel +import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.actions.SaveButton +import com.vitorpamplona.amethyst.ui.navigation.INav +import com.vitorpamplona.amethyst.ui.navigation.rememberHeightDecreaser +import com.vitorpamplona.amethyst.ui.note.ArrowBackIcon +import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountContent +import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountViewModel +import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun NIP47SetupScreen( + accountViewModel: AccountViewModel, + nav: INav, + nip47: String?, +) { + val postViewModel: UpdateZapAmountViewModel = + viewModel( + key = "UpdateZapAmountViewModel", + factory = UpdateZapAmountViewModel.Factory(accountViewModel.account.settings), + ) + + Scaffold( + topBar = { + TopAppBar( + scrollBehavior = rememberHeightDecreaser(), + title = { Text(stringRes(id = R.string.wallet_connect)) }, + navigationIcon = { + IconButton( + onClick = { + postViewModel.cancel() + nav.popBack() + }, + modifier = Modifier, + ) { + ArrowBackIcon() + } + }, + actions = { + SaveButton( + onPost = { + postViewModel.sendPost() + nav.popBack() + }, + isActive = postViewModel.hasChanged(), + ) + }, + ) + }, + ) { + Column(Modifier.padding(it)) { + UpdateZapAmountContent(postViewModel, onClose = { + postViewModel.cancel() + nav.popBack() + }, nip47, accountViewModel) + } + } +} diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index e205c7c20..93f1b73d2 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -610,6 +610,7 @@ Light Dark Application Preferences + Wallet Connect Language Theme Image Preview