diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c22a472ac..518e6a539 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -43,6 +43,13 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt
index 3afecdcb7..49823b3e4 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt
@@ -21,6 +21,8 @@ import com.vitorpamplona.amethyst.LocalPreferences
import com.vitorpamplona.amethyst.ServiceManager
import com.vitorpamplona.amethyst.service.nip19.Nip19
import com.vitorpamplona.amethyst.service.relays.Client
+import com.vitorpamplona.amethyst.ui.navigation.Route
+import com.vitorpamplona.amethyst.ui.note.Nip47
import com.vitorpamplona.amethyst.ui.screen.AccountScreen
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
import com.vitorpamplona.amethyst.ui.theme.AmethystTheme
@@ -28,6 +30,8 @@ import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
+import java.net.URLEncoder
+import java.nio.charset.StandardCharsets
class MainActivity : FragmentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
@@ -40,6 +44,14 @@ class MainActivity : FragmentActivity() {
Nip19.Type.EVENT -> "Event/${nip19.hex}"
Nip19.Type.ADDRESS -> "Note/${nip19.hex}"
else -> null
+ } ?: try {
+ intent?.data?.toString()?.let {
+ Nip47.parse(it)
+ val encodedUri = URLEncoder.encode(it, StandardCharsets.UTF_8.toString())
+ Route.Home.base + "?nip47=" + encodedUri
+ }
+ } catch (e: Exception) {
+ null
}
Coil.setImageLoader {
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt
index bba99be7a..d7418272c 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt
@@ -1,8 +1,12 @@
package com.vitorpamplona.amethyst.ui.navigation
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
@@ -39,6 +43,7 @@ fun AppNavigation(
nextPage: String? = null
) {
val homePagerState = rememberPagerState()
+ var actionableNextPage by remember { mutableStateOf(nextPage) }
// Avoids creating ViewModels for performance reasons (up to 1 second delays)
val accountState by accountViewModel.accountLiveData.observeAsState()
@@ -76,8 +81,9 @@ fun AppNavigation(
}
Route.Home.let { route ->
- composable(route.route, route.arguments, content = {
+ composable(route.route, route.arguments, content = { it ->
val scrollToTop = it.arguments?.getBoolean("scrollToTop") ?: false
+ val nip47 = it.arguments?.getString("nip47")
HomeScreen(
homeFeedViewModel = homeFeedViewModel,
@@ -85,13 +91,17 @@ fun AppNavigation(
accountViewModel = accountViewModel,
navController = navController,
pagerState = homePagerState,
- scrollToTop = scrollToTop
+ scrollToTop = scrollToTop,
+ nip47 = nip47
)
// Avoids running scroll to top when back button is pressed
if (scrollToTop) {
it.arguments?.remove("scrollToTop")
}
+ if (nip47 != null) {
+ it.arguments?.remove("nip47")
+ }
})
}
@@ -178,7 +188,10 @@ fun AppNavigation(
}
}
- if (nextPage != null) {
- navController.navigate(nextPage)
+ actionableNextPage?.let {
+ LaunchedEffect(it) {
+ navController.navigate(it)
+ }
+ actionableNextPage = null
}
}
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt
index 66fd2fa05..ddbe4d307 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt
@@ -24,9 +24,12 @@ sealed class Route(
get() = route.substringBefore("?")
object Home : Route(
- route = "Home?scrollToTop={scrollToTop}",
+ route = "Home?scrollToTop={scrollToTop}&nip47={nip47}",
icon = R.drawable.ic_home,
- arguments = listOf(navArgument("scrollToTop") { type = NavType.BoolType; defaultValue = false }),
+ arguments = listOf(
+ navArgument("scrollToTop") { type = NavType.BoolType; defaultValue = false },
+ navArgument("nip47") { type = NavType.StringType; nullable = true; defaultValue = null }
+ ),
hasNewItems = { accountViewModel, cache -> homeHasNewItems(accountViewModel, cache) }
)
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt
index 8315f59b5..7b0899c6b 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt
@@ -49,6 +49,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
@@ -165,17 +166,40 @@ class UpdateZapAmountViewModel : ViewModel() {
walletConnectSecret.text != (account?.zapPaymentRequest?.secret ?: "")
)
}
+
+ fun updateNIP47(uri: String) {
+ val contact = Nip47.parse(uri)
+ if (contact != null) {
+ walletConnectPubkey =
+ TextFieldValue(contact.pubKeyHex)
+ walletConnectRelay =
+ TextFieldValue(contact.relayUri ?: "")
+ walletConnectSecret =
+ TextFieldValue(contact.secret ?: "")
+ }
+ }
}
@OptIn(ExperimentalLayoutApi::class)
@Composable
-fun UpdateZapAmountDialog(onClose: () -> Unit, account: Account) {
+fun UpdateZapAmountDialog(onClose: () -> Unit, account: Account, nip47uri: String? = null) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val postViewModel: UpdateZapAmountViewModel = viewModel()
+ val uri = LocalUriHandler.current
LaunchedEffect(account) {
postViewModel.load(account)
+ if (nip47uri != null) {
+ try {
+ postViewModel.updateNIP47(nip47uri)
+ } catch (e: IllegalArgumentException) {
+ scope.launch {
+ Toast.makeText(context, e.message, Toast.LENGTH_SHORT)
+ .show()
+ }
+ }
+ }
}
Dialog(
@@ -299,6 +323,18 @@ fun UpdateZapAmountDialog(onClose: () -> Unit, account: Account) {
stringResource(id = R.string.wallet_connect_service),
Modifier.weight(1f)
)
+
+ IconButton(onClick = {
+ runCatching { uri.openUri("https://nwc.getalby.com/apps/new?c=Amethyst") }
+ }) {
+ Icon(
+ painter = painterResource(R.drawable.alby),
+ null,
+ modifier = Modifier.size(24.dp),
+ tint = Color.Unspecified
+ )
+ }
+
IconButton(onClick = {
qrScanning = true
}) {
@@ -330,15 +366,7 @@ fun UpdateZapAmountDialog(onClose: () -> Unit, account: Account) {
qrScanning = false
if (!it.isNullOrEmpty()) {
try {
- val contact = Nip47.parse(it)
- if (contact != null) {
- postViewModel.walletConnectPubkey =
- TextFieldValue(contact.pubKeyHex)
- postViewModel.walletConnectRelay =
- TextFieldValue(contact.relayUri ?: "")
- postViewModel.walletConnectSecret =
- TextFieldValue(contact.secret ?: "")
- }
+ postViewModel.updateNIP47(it)
} catch (e: IllegalArgumentException) {
scope.launch {
Toast.makeText(context, e.message, Toast.LENGTH_SHORT)
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt
index 15676ba3c..c191de3aa 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HomeScreen.kt
@@ -11,7 +11,11 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
+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.Modifier
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.stringResource
@@ -28,6 +32,7 @@ import com.vitorpamplona.amethyst.service.NostrHomeDataSource
import com.vitorpamplona.amethyst.ui.dal.HomeConversationsFeedFilter
import com.vitorpamplona.amethyst.ui.dal.HomeNewThreadFeedFilter
import com.vitorpamplona.amethyst.ui.navigation.Route
+import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountDialog
import com.vitorpamplona.amethyst.ui.screen.FeedView
import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedViewModel
import com.vitorpamplona.amethyst.ui.screen.NostrHomeRepliesFeedViewModel
@@ -42,10 +47,12 @@ fun HomeScreen(
accountViewModel: AccountViewModel,
navController: NavController,
pagerState: PagerState,
- scrollToTop: Boolean = false
+ scrollToTop: Boolean = false,
+ nip47: String? = null
) {
val coroutineScope = rememberCoroutineScope()
val account = accountViewModel.accountLiveData.value?.account ?: return
+ var wantsToAddNip47 by remember { mutableStateOf(nip47) }
LaunchedEffect(accountViewModel) {
HomeNewThreadFeedFilter.account = account
@@ -55,6 +62,10 @@ fun HomeScreen(
repliesFeedViewModel.invalidateData()
}
+ if (wantsToAddNip47 != null) {
+ UpdateZapAmountDialog({ wantsToAddNip47 = null }, account = account, wantsToAddNip47)
+ }
+
val lifeCycleOwner = LocalLifecycleOwner.current
DisposableEffect(accountViewModel) {
val observer = LifecycleEventObserver { _, event ->
diff --git a/app/src/main/res/drawable/alby.xml b/app/src/main/res/drawable/alby.xml
index 1188a62fc..cb036c35e 100644
--- a/app/src/main/res/drawable/alby.xml
+++ b/app/src/main/res/drawable/alby.xml
@@ -1,39 +1,58 @@
+ android:width="489dp"
+ android:height="489dp"
+ android:viewportWidth="489"
+ android:viewportHeight="489">
+ android:pathData="M89.58,181.77C96.83,182.51 103.84,181.66 110.26,179.49L110.42,179.63L110.66,179.87C83.35,210.92 64.09,251.1 56.14,295.56C50.5,327.03 67.39,357.29 95.35,370.61C140.92,392.29 191.9,404.42 245.64,404.42C299.39,404.42 349.32,392.54 394.53,371.27C422.59,358.07 439.6,327.82 434.06,296.31C426.2,251.6 406.52,211.48 379.48,179.96C345.33,140.15 379.58,179.8 379.58,179.8C379.58,179.8 391.32,182.34 397.62,181.9C421.93,180.22 441.52,160.37 442.89,136.03C444.51,106.88 420.52,82.9 391.36,84.54C367.36,85.89 347.63,105.01 345.58,128.97C344.95,136.44 346.01,143.62 348.41,150.15L348.02,150.54L347.79,150.77C318.32,129.03 283.17,116.22 245.05,116.22C206.93,116.22 171.54,129.12 141.99,151.01L141.77,150.78L141.4,150.42L140.69,149.71C143.01,143.22 144.01,136.11 143.33,128.71C141.16,104.88 121.47,85.9 97.57,84.55C68.36,82.92 44.37,106.91 46.01,136.09C47.34,159.78 65.97,179.34 89.56,181.78L89.58,181.77Z"
+ android:strokeWidth="19.962"
+ android:fillColor="#ffffff"
+ android:strokeColor="#ffffff"/>
-
-
-
+
+
+
+
+
+
+
+