chore: merge the develop branch into master #1
@@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:autoMirrored="true"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960">
|
||||||
|
<path
|
||||||
|
android:fillColor="#000000"
|
||||||
|
android:pathData="M647,520L160,520L160,440L647,440L423,216L480,160L800,480L480,800L423,744L647,520Z" />
|
||||||
|
</vector>
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
android:viewportWidth="960"
|
android:viewportWidth="960"
|
||||||
android:viewportHeight="960"
|
android:viewportHeight="960">
|
||||||
android:tint="?attr/colorControlNormal">
|
<path
|
||||||
<path
|
android:fillColor="#000000"
|
||||||
android:fillColor="@android:color/white"
|
android:pathData="M256,760L200,704L424,480L200,256L256,200L480,424L704,200L760,256L536,480L760,704L704,760L480,536L256,760Z" />
|
||||||
android:pathData="M256,760L200,704L424,480L200,256L256,200L480,424L704,200L760,256L536,480L760,704L704,760L480,536L256,760Z"/>
|
|
||||||
</vector>
|
</vector>
|
||||||
|
|||||||
@@ -2,9 +2,8 @@
|
|||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="960"
|
android:viewportWidth="960"
|
||||||
android:viewportHeight="960"
|
android:viewportHeight="960">
|
||||||
android:tint="?attr/colorControlNormal">
|
<path
|
||||||
<path
|
android:fillColor="#000000"
|
||||||
android:fillColor="@android:color/white"
|
android:pathData="M336,680L280,624L424,480L280,337L336,281L480,425L623,281L679,337L535,480L679,624L623,680L480,536L336,680Z" />
|
||||||
android:pathData="M336,680L280,624L424,480L280,337L336,281L480,425L623,281L679,337L535,480L679,624L623,680L480,536L336,680Z"/>
|
|
||||||
</vector>
|
</vector>
|
||||||
|
|||||||
@@ -3,29 +3,36 @@ package su.reya.coop.screens
|
|||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.widthIn
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.BasicTextField
|
import androidx.compose.foundation.text.BasicTextField
|
||||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
|
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.InputChip
|
import androidx.compose.material3.InputChip
|
||||||
import androidx.compose.material3.ListItemDefaults
|
import androidx.compose.material3.ListItemDefaults
|
||||||
|
import androidx.compose.material3.LocalMinimumInteractiveComponentSize
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.PlainTooltip
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.SegmentedListItem
|
import androidx.compose.material3.SegmentedListItem
|
||||||
import androidx.compose.material3.SnackbarHost
|
import androidx.compose.material3.SnackbarHost
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TooltipAnchorPosition
|
||||||
|
import androidx.compose.material3.TooltipBox
|
||||||
|
import androidx.compose.material3.TooltipDefaults
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
|
import androidx.compose.material3.rememberTooltipState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -37,9 +44,11 @@ import androidx.compose.runtime.snapshots.SnapshotStateList
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.SolidColor
|
import androidx.compose.ui.graphics.SolidColor
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import coop.composeapp.generated.resources.Res
|
import coop.composeapp.generated.resources.Res
|
||||||
import coop.composeapp.generated.resources.ic_arrow_back
|
import coop.composeapp.generated.resources.ic_arrow_back
|
||||||
|
import coop.composeapp.generated.resources.ic_arrow_next
|
||||||
import coop.composeapp.generated.resources.ic_close_small
|
import coop.composeapp.generated.resources.ic_close_small
|
||||||
import coop.composeapp.generated.resources.ic_scanner
|
import coop.composeapp.generated.resources.ic_scanner
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
@@ -60,7 +69,10 @@ fun NewChatScreen(
|
|||||||
val snackbarHostState = LocalSnackbarHostState.current
|
val snackbarHostState = LocalSnackbarHostState.current
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
val viewModel = LocalNostrViewModel.current
|
val viewModel = LocalNostrViewModel.current
|
||||||
|
val contactList by viewModel.contactList.collectAsState(initial = emptySet())
|
||||||
|
|
||||||
|
val createGroup = remember { mutableStateOf(false) }
|
||||||
|
val searchResults = remember { mutableStateListOf<PublicKey>() }
|
||||||
val selectedReceivers = remember { mutableStateListOf<PublicKey>() }
|
val selectedReceivers = remember { mutableStateListOf<PublicKey>() }
|
||||||
var query by remember { mutableStateOf("") }
|
var query by remember { mutableStateOf("") }
|
||||||
|
|
||||||
@@ -71,7 +83,28 @@ fun NewChatScreen(
|
|||||||
LaunchedEffect(query) {
|
LaunchedEffect(query) {
|
||||||
if (query.length >= 3) {
|
if (query.length >= 3) {
|
||||||
delay(500) // 500ms debounce
|
delay(500) // 500ms debounce
|
||||||
// TODO: Implement search
|
|
||||||
|
if (query.startsWith("npub1")) {
|
||||||
|
val pubkey = try {
|
||||||
|
PublicKey.parse(query)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
if (pubkey != null) {
|
||||||
|
selectedReceivers.add(pubkey)
|
||||||
|
}
|
||||||
|
} else if (query.contains("@")) {
|
||||||
|
val pubkey = viewModel.searchByAddress(query)
|
||||||
|
if (pubkey != null) {
|
||||||
|
selectedReceivers.add(pubkey)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val results = viewModel.searchByNostr(query)
|
||||||
|
searchResults.clear()
|
||||||
|
searchResults.addAll(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
query = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +120,12 @@ fun NewChatScreen(
|
|||||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text("New Chat") },
|
title = {
|
||||||
|
Text(
|
||||||
|
text = if (createGroup.value) "New group chat" else "New chat",
|
||||||
|
style = MaterialTheme.typography.titleMediumEmphasized
|
||||||
|
)
|
||||||
|
},
|
||||||
colors = TopAppBarDefaults.topAppBarColors(
|
colors = TopAppBarDefaults.topAppBarColors(
|
||||||
containerColor = MaterialTheme.colorScheme.surfaceContainer,
|
containerColor = MaterialTheme.colorScheme.surfaceContainer,
|
||||||
),
|
),
|
||||||
@@ -109,6 +147,37 @@ fun NewChatScreen(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
floatingActionButton = {
|
||||||
|
if (selectedReceivers.isNotEmpty()) {
|
||||||
|
TooltipBox(
|
||||||
|
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
|
||||||
|
TooltipAnchorPosition.Above,
|
||||||
|
spacingBetweenTooltipAndAnchor = 8.dp,
|
||||||
|
),
|
||||||
|
tooltip = {
|
||||||
|
PlainTooltip { Text("Next") }
|
||||||
|
},
|
||||||
|
state = rememberTooltipState(),
|
||||||
|
) {
|
||||||
|
ExtendedFloatingActionButton(
|
||||||
|
onClick = {
|
||||||
|
val roomId = viewModel.createChatRoom(selectedReceivers.toList())
|
||||||
|
navController.navigate(Screen.Chat(roomId))
|
||||||
|
},
|
||||||
|
expanded = false,
|
||||||
|
icon = {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(Res.drawable.ic_arrow_next),
|
||||||
|
contentDescription = "Next"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
text = { Text("Next") },
|
||||||
|
containerColor = MaterialTheme.colorScheme.tertiary,
|
||||||
|
contentColor = MaterialTheme.colorScheme.onTertiary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
content = { innerPadding ->
|
content = { innerPadding ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -119,52 +188,57 @@ fun NewChatScreen(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
shape = RoundedCornerShape(28.dp),
|
shape = RoundedCornerShape(24.dp),
|
||||||
color = MaterialTheme.colorScheme.surface,
|
color = MaterialTheme.colorScheme.surface,
|
||||||
) {
|
) {
|
||||||
FlowRow(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
.fillMaxWidth()
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
.padding(16.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
verticalAlignment = Alignment.Top,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "To:",
|
text = "To:",
|
||||||
modifier = Modifier.align(Alignment.Top),
|
style = MaterialTheme.typography.bodyMedium.copy(
|
||||||
style = MaterialTheme.typography.labelMediumEmphasized,
|
fontWeight = FontWeight.SemiBold,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
),
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
)
|
)
|
||||||
selectedReceivers.forEach { receiver ->
|
Spacer(modifier = Modifier.size(16.dp))
|
||||||
ReceiverChip(
|
Column(
|
||||||
pubkey = receiver,
|
modifier = Modifier.weight(1f),
|
||||||
onRemove = { selectedReceivers.remove(receiver) }
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
) {
|
||||||
|
selectedReceivers.forEach { receiver ->
|
||||||
|
ReceiverChip(
|
||||||
|
pubkey = receiver,
|
||||||
|
onRemove = { selectedReceivers.remove(receiver) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
BasicTextField(
|
||||||
|
value = query,
|
||||||
|
onValueChange = { query = it },
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
textStyle = MaterialTheme.typography.bodyMedium.copy(
|
||||||
|
color = MaterialTheme.colorScheme.onSurface
|
||||||
|
),
|
||||||
|
cursorBrush = SolidColor(MaterialTheme.colorScheme.primary),
|
||||||
|
decorationBox = { innerTextField ->
|
||||||
|
Box(contentAlignment = Alignment.CenterStart) {
|
||||||
|
if (query.isEmpty()) {
|
||||||
|
Text(
|
||||||
|
"Type a npub or address",
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(
|
||||||
|
alpha = 0.5f
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
innerTextField()
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
BasicTextField(
|
|
||||||
value = query,
|
|
||||||
onValueChange = { query = it },
|
|
||||||
modifier = Modifier
|
|
||||||
.widthIn(min = 50.dp)
|
|
||||||
.align(Alignment.CenterVertically),
|
|
||||||
textStyle = MaterialTheme.typography.bodyMedium.copy(
|
|
||||||
color = MaterialTheme.colorScheme.onSurface
|
|
||||||
),
|
|
||||||
cursorBrush = SolidColor(MaterialTheme.colorScheme.primary),
|
|
||||||
decorationBox = { innerTextField ->
|
|
||||||
Box(contentAlignment = Alignment.CenterStart) {
|
|
||||||
if (query.isEmpty() && selectedReceivers.isEmpty()) {
|
|
||||||
Text(
|
|
||||||
"Type a npub or address",
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(
|
|
||||||
alpha = 0.5f
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
innerTextField()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.size(16.dp))
|
Spacer(modifier = Modifier.size(16.dp))
|
||||||
@@ -173,15 +247,28 @@ fun NewChatScreen(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
) {
|
) {
|
||||||
// TODO: add result list
|
if (searchResults.isNotEmpty()) {
|
||||||
ContactList(
|
ContactList(
|
||||||
selectedReceivers = selectedReceivers,
|
items = searchResults,
|
||||||
onContactClick = { pubkey ->
|
selectedReceivers = selectedReceivers,
|
||||||
val roomId = viewModel.createChatRoom(listOf(pubkey))
|
onContactClick = { pubkey ->
|
||||||
navController.navigate(Screen.Chat(roomId))
|
val roomId = viewModel.createChatRoom(listOf(pubkey))
|
||||||
}
|
navController.navigate(Screen.Chat(roomId))
|
||||||
)
|
},
|
||||||
Spacer(modifier = Modifier.size(16.dp))
|
)
|
||||||
|
Spacer(modifier = Modifier.size(16.dp))
|
||||||
|
} else {
|
||||||
|
ContactList(
|
||||||
|
title = "Contacts",
|
||||||
|
items = contactList.toList(),
|
||||||
|
selectedReceivers = selectedReceivers,
|
||||||
|
onContactClick = { pubkey ->
|
||||||
|
val roomId = viewModel.createChatRoom(listOf(pubkey))
|
||||||
|
navController.navigate(Screen.Chat(roomId))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.size(16.dp))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,49 +288,62 @@ fun ReceiverChip(
|
|||||||
val displayName = profile?.name ?: profile?.displayName ?: pubkey.short()
|
val displayName = profile?.name ?: profile?.displayName ?: pubkey.short()
|
||||||
val picture = profile?.picture
|
val picture = profile?.picture
|
||||||
|
|
||||||
InputChip(
|
CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) {
|
||||||
selected = true,
|
InputChip(
|
||||||
onClick = onRemove,
|
selected = true,
|
||||||
label = { Text(displayName) },
|
onClick = onRemove,
|
||||||
avatar = {
|
label = {
|
||||||
Avatar(
|
Text(
|
||||||
picture = picture,
|
text = displayName,
|
||||||
description = displayName,
|
style = MaterialTheme.typography.bodyMedium.copy(
|
||||||
size = 24.dp
|
fontWeight = FontWeight.SemiBold
|
||||||
)
|
)
|
||||||
},
|
)
|
||||||
trailingIcon = {
|
},
|
||||||
Icon(
|
avatar = {
|
||||||
painter = painterResource(Res.drawable.ic_close_small),
|
Avatar(
|
||||||
contentDescription = "Close"
|
picture = picture,
|
||||||
)
|
description = displayName,
|
||||||
}
|
size = 24.dp
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
trailingIcon = {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(Res.drawable.ic_close_small),
|
||||||
|
contentDescription = "Close"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
shape = RoundedCornerShape(24.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun ContactList(
|
fun ContactList(
|
||||||
|
title: String? = null,
|
||||||
|
items: List<PublicKey>,
|
||||||
selectedReceivers: SnapshotStateList<PublicKey>,
|
selectedReceivers: SnapshotStateList<PublicKey>,
|
||||||
onContactClick: (PublicKey) -> Unit
|
onContactClick: (PublicKey) -> Unit
|
||||||
) {
|
) {
|
||||||
val viewModel = LocalNostrViewModel.current
|
if (items.isEmpty()) return
|
||||||
val contactList by viewModel.contactList.collectAsState(initial = emptySet())
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
verticalArrangement = Arrangement.spacedBy(ListItemDefaults.SegmentedGap),
|
verticalArrangement = Arrangement.spacedBy(ListItemDefaults.SegmentedGap),
|
||||||
) {
|
) {
|
||||||
Text(
|
if (title != null) {
|
||||||
text = "Contacts",
|
Text(
|
||||||
style = MaterialTheme.typography.titleLargeEmphasized,
|
text = title,
|
||||||
)
|
style = MaterialTheme.typography.titleMediumEmphasized,
|
||||||
Spacer(modifier = Modifier.size(8.dp))
|
)
|
||||||
contactList.forEachIndexed { index, item ->
|
Spacer(modifier = Modifier.size(8.dp))
|
||||||
|
}
|
||||||
|
items.forEachIndexed { index, item ->
|
||||||
ContactListItem(
|
ContactListItem(
|
||||||
pubkey = item,
|
pubkey = item,
|
||||||
index = index,
|
index = index,
|
||||||
total = contactList.size,
|
total = items.size,
|
||||||
isSelected = selectedReceivers.contains(item),
|
isSelected = selectedReceivers.contains(item),
|
||||||
onClick = { onContactClick(item) },
|
onClick = { onContactClick(item) },
|
||||||
onLongClick = {
|
onLongClick = {
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ class Nostr {
|
|||||||
// Bootstrap relays
|
// Bootstrap relays
|
||||||
client?.addRelay(RelayUrl.parse("wss://relay.primal.net"))
|
client?.addRelay(RelayUrl.parse("wss://relay.primal.net"))
|
||||||
client?.addRelay(RelayUrl.parse("wss://user.kindpag.es"))
|
client?.addRelay(RelayUrl.parse("wss://user.kindpag.es"))
|
||||||
|
client?.addRelay(RelayUrl.parse("wss://purplepag.es"))
|
||||||
|
|
||||||
// Add search relay
|
// Add search relay
|
||||||
client?.addRelay(
|
client?.addRelay(
|
||||||
@@ -638,18 +639,18 @@ class Nostr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun searchByAddress(query: String): List<PublicKey> {
|
suspend fun searchByAddress(query: String): PublicKey {
|
||||||
try {
|
try {
|
||||||
val address = Nip05Address.parse(query)
|
val address = Nip05Address.parse(query)
|
||||||
val profile = profileFromAddress(HttpClient(), address)
|
val profile = profileFromAddress(HttpClient(), address)
|
||||||
|
|
||||||
return listOf(profile.publicKey())
|
return profile.publicKey()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
throw IllegalStateException("Failed to search address: ${e.message}", e)
|
throw IllegalStateException("Failed to search address: ${e.message}", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun searchByNostr(query: String) {
|
suspend fun searchByNostr(query: String): List<PublicKey> {
|
||||||
try {
|
try {
|
||||||
val kinds = listOf(Kind.fromStd(KindStandard.METADATA))
|
val kinds = listOf(Kind.fromStd(KindStandard.METADATA))
|
||||||
val filter = Filter().kinds(kinds).search(query).limit(10u)
|
val filter = Filter().kinds(kinds).search(query).limit(10u)
|
||||||
@@ -672,6 +673,8 @@ class Nostr {
|
|||||||
results.add(event.event!!.author())
|
results.add(event.event!!.author())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
throw IllegalStateException("Failed to search nostr: ${e.message}", e)
|
throw IllegalStateException("Failed to search nostr: ${e.message}", e)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -380,6 +380,24 @@ class NostrViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun searchByAddress(query: String): PublicKey? {
|
||||||
|
try {
|
||||||
|
return nostr.searchByAddress(query)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
showError("Error: ${e.message}")
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun searchByNostr(query: String): List<PublicKey> {
|
||||||
|
try {
|
||||||
|
return nostr.searchByNostr(query)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
showError("Error: ${e.message}")
|
||||||
|
}
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun PublicKey.short(): String {
|
fun PublicKey.short(): String {
|
||||||
|
|||||||
Reference in New Issue
Block a user