mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-04-08 11:58:03 +02:00
Improves relay list NIP-11 caching, updates NIP-11 properties in the document and adds icon rendering from the NIP11 document.
This commit is contained in:
parent
2ee4b24c9b
commit
dd160ecb71
@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.service
|
||||
import android.util.Log
|
||||
import android.util.LruCache
|
||||
import com.vitorpamplona.quartz.encoders.Nip11RelayInformation
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import okhttp3.Call
|
||||
import okhttp3.Callback
|
||||
@ -31,9 +32,21 @@ import okhttp3.Response
|
||||
import java.io.IOException
|
||||
|
||||
object Nip11CachedRetriever {
|
||||
val relayInformationDocumentCache = LruCache<String, Nip11RelayInformation>(100)
|
||||
open class RetrieveResult(val time: Long)
|
||||
|
||||
class RetrieveResultError(val error: Nip11Retriever.ErrorCode, val msg: String? = null) : RetrieveResult(TimeUtils.now())
|
||||
|
||||
class RetrieveResultSuccess(val data: Nip11RelayInformation) : RetrieveResult(TimeUtils.now())
|
||||
|
||||
val relayInformationDocumentCache = LruCache<String, RetrieveResult?>(100)
|
||||
val retriever = Nip11Retriever()
|
||||
|
||||
fun getFromCache(dirtyUrl: String): Nip11RelayInformation? {
|
||||
val result = relayInformationDocumentCache.get(retriever.cleanUrl(dirtyUrl)) ?: return null
|
||||
if (result is RetrieveResultSuccess) return result.data
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun loadRelayInfo(
|
||||
dirtyUrl: String,
|
||||
onInfo: (Nip11RelayInformation) -> Unit,
|
||||
@ -43,17 +56,40 @@ object Nip11CachedRetriever {
|
||||
val doc = relayInformationDocumentCache.get(url)
|
||||
|
||||
if (doc != null) {
|
||||
onInfo(doc)
|
||||
if (doc is RetrieveResultSuccess) {
|
||||
onInfo(doc.data)
|
||||
} else if (doc is RetrieveResultError) {
|
||||
if (TimeUtils.now() - doc.time < TimeUtils.ONE_HOUR) {
|
||||
onError(dirtyUrl, doc.error, null)
|
||||
} else {
|
||||
Nip11Retriever()
|
||||
.loadRelayInfo(
|
||||
url = url,
|
||||
dirtyUrl = dirtyUrl,
|
||||
onInfo = {
|
||||
relayInformationDocumentCache.put(url, RetrieveResultSuccess(it))
|
||||
onInfo(it)
|
||||
},
|
||||
onError = { dirtyUrl, code, errorMsg ->
|
||||
relayInformationDocumentCache.put(url, RetrieveResultError(code, errorMsg))
|
||||
onError(url, code, errorMsg)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Nip11Retriever()
|
||||
.loadRelayInfo(
|
||||
url,
|
||||
dirtyUrl,
|
||||
url = url,
|
||||
dirtyUrl = dirtyUrl,
|
||||
onInfo = {
|
||||
relayInformationDocumentCache.put(url, it)
|
||||
relayInformationDocumentCache.put(url, RetrieveResultSuccess(it))
|
||||
onInfo(it)
|
||||
},
|
||||
onError,
|
||||
onError = { dirtyUrl, code, errorMsg ->
|
||||
relayInformationDocumentCache.put(url, RetrieveResultError(code, errorMsg))
|
||||
onError(url, code, errorMsg)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -81,6 +117,7 @@ class Nip11Retriever {
|
||||
onInfo: (Nip11RelayInformation) -> Unit,
|
||||
onError: (String, ErrorCode, String?) -> Unit,
|
||||
) {
|
||||
checkNotInMainThread()
|
||||
try {
|
||||
val request: Request =
|
||||
Request.Builder().header("Accept", "application/nostr+json").url(url).build()
|
||||
|
@ -79,6 +79,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.RelayBriefInfoCache
|
||||
import com.vitorpamplona.amethyst.model.RelaySetupInfo
|
||||
import com.vitorpamplona.amethyst.service.Nip11CachedRetriever
|
||||
import com.vitorpamplona.amethyst.service.Nip11Retriever
|
||||
import com.vitorpamplona.amethyst.service.relays.Constants
|
||||
import com.vitorpamplona.amethyst.service.relays.Constants.defaultRelays
|
||||
@ -193,8 +194,10 @@ fun NewRelayListView(
|
||||
onToggleSearch = { postViewModel.toggleSearch(it) },
|
||||
onDelete = { postViewModel.deleteRelay(it) },
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
) {
|
||||
onClose()
|
||||
nav(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -410,9 +413,14 @@ fun ServerConfigClickableLine(
|
||||
modifier = Modifier.padding(vertical = 5.dp),
|
||||
) {
|
||||
Column(Modifier.clickable(onClick = onClick)) {
|
||||
val iconUrlFromRelayInfoDoc =
|
||||
remember(item) {
|
||||
Nip11CachedRetriever.getFromCache(item.url)?.icon
|
||||
}
|
||||
|
||||
RenderRelayIcon(
|
||||
item.briefInfo.displayUrl,
|
||||
item.briefInfo.favIcon,
|
||||
iconUrlFromRelayInfoDoc ?: item.briefInfo.favIcon,
|
||||
loadProfilePicture,
|
||||
MaterialTheme.colorScheme.largeRelayIconModifier,
|
||||
)
|
||||
|
@ -62,7 +62,9 @@ class NewRelayListViewModel : ViewModel() {
|
||||
_relays.value.forEach { item ->
|
||||
Nip11CachedRetriever.loadRelayInfo(
|
||||
dirtyUrl = item.url,
|
||||
onInfo = { togglePaidRelay(item, it.limitation?.payment_required ?: false) },
|
||||
onInfo = {
|
||||
togglePaidRelay(item, it.limitation?.payment_required ?: false)
|
||||
},
|
||||
onError = { url, errorCode, exceptionMessage -> },
|
||||
)
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ fun RelayInformationDialog(
|
||||
Column {
|
||||
RenderRelayIcon(
|
||||
relayBriefInfo.displayUrl,
|
||||
relayBriefInfo.favIcon,
|
||||
relayInfo.icon ?: relayBriefInfo.favIcon,
|
||||
automaticallyShowProfilePicture,
|
||||
MaterialTheme.colorScheme.largeRelayIconModifier,
|
||||
)
|
||||
@ -121,7 +121,12 @@ fun RelayInformationDialog(
|
||||
|
||||
Section(stringResource(R.string.owner))
|
||||
|
||||
relayInfo.pubkey?.let { DisplayOwnerInformation(it, accountViewModel, nav) }
|
||||
relayInfo.pubkey?.let {
|
||||
DisplayOwnerInformation(it, accountViewModel) {
|
||||
onClose()
|
||||
nav(it)
|
||||
}
|
||||
}
|
||||
|
||||
Section(stringResource(R.string.software))
|
||||
|
||||
@ -170,12 +175,14 @@ fun RelayInformationDialog(
|
||||
|
||||
relayInfo.limitation?.let {
|
||||
Section(stringResource(R.string.limitations))
|
||||
val authRequired = it.auth_required ?: false
|
||||
val authRequiredText =
|
||||
if (authRequired) stringResource(R.string.yes) else stringResource(R.string.no)
|
||||
val paymentRequired = it.payment_required ?: false
|
||||
if (it.auth_required ?: false) stringResource(R.string.yes) else stringResource(R.string.no)
|
||||
|
||||
val paymentRequiredText =
|
||||
if (paymentRequired) stringResource(R.string.yes) else stringResource(R.string.no)
|
||||
if (it.payment_required ?: false) stringResource(R.string.yes) else stringResource(R.string.no)
|
||||
|
||||
val restrictedWritesText =
|
||||
if (it.restricted_writes ?: false) stringResource(R.string.yes) else stringResource(R.string.no)
|
||||
|
||||
Column {
|
||||
SectionContent(
|
||||
@ -184,7 +191,7 @@ fun RelayInformationDialog(
|
||||
SectionContent(
|
||||
"${stringResource(R.string.subscriptions)}: ${it.max_subscriptions ?: 0}",
|
||||
)
|
||||
SectionContent("${stringResource(R.string.filters)}: ${it.max_subscriptions ?: 0}")
|
||||
SectionContent("${stringResource(R.string.filters)}: ${it.max_filters ?: 0}")
|
||||
SectionContent(
|
||||
"${stringResource(R.string.subscription_id_length)}: ${it.max_subid_length ?: 0}",
|
||||
)
|
||||
@ -195,9 +202,13 @@ fun RelayInformationDialog(
|
||||
SectionContent(
|
||||
"${stringResource(R.string.content_length)}: ${it.max_content_length ?: 0}",
|
||||
)
|
||||
SectionContent(
|
||||
"${stringResource(R.string.max_limit)}: ${it.max_limit ?: 0}",
|
||||
)
|
||||
SectionContent("${stringResource(R.string.minimum_pow)}: ${it.min_pow_difficulty ?: 0}")
|
||||
SectionContent("${stringResource(R.string.auth)}: $authRequiredText")
|
||||
SectionContent("${stringResource(R.string.payment)}: $paymentRequiredText")
|
||||
SectionContent("${stringResource(R.string.restricted_writes)}: $restrictedWritesText")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@ import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
@ -51,6 +52,7 @@ import androidx.lifecycle.map
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.RelayBriefInfoCache
|
||||
import com.vitorpamplona.amethyst.service.Nip11CachedRetriever
|
||||
import com.vitorpamplona.amethyst.service.Nip11Retriever
|
||||
import com.vitorpamplona.amethyst.ui.actions.RelayInformationDialog
|
||||
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
|
||||
@ -61,7 +63,6 @@ import com.vitorpamplona.amethyst.ui.theme.Size15dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdStartPadding
|
||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.ui.theme.relayIconModifier
|
||||
import com.vitorpamplona.quartz.encoders.Nip11RelayInformation
|
||||
|
||||
@Composable
|
||||
public fun RelayBadgesHorizontal(
|
||||
@ -132,11 +133,27 @@ fun RenderRelay(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
var relayInfo: Nip11RelayInformation? by remember { mutableStateOf(null) }
|
||||
val relayInfo by
|
||||
produceState(
|
||||
initialValue = Nip11CachedRetriever.getFromCache(relay.url),
|
||||
) {
|
||||
if (value == null) {
|
||||
accountViewModel.retrieveRelayDocument(
|
||||
relay.url,
|
||||
onInfo = {
|
||||
value = it
|
||||
},
|
||||
onError = { url, errorCode, exceptionMessage ->
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (relayInfo != null) {
|
||||
var openRelayDialog by remember { mutableStateOf(false) }
|
||||
|
||||
if (openRelayDialog && relayInfo != null) {
|
||||
RelayInformationDialog(
|
||||
onClose = { relayInfo = null },
|
||||
onClose = { openRelayDialog = false },
|
||||
relayInfo = relayInfo!!,
|
||||
relayBriefInfo = relay,
|
||||
accountViewModel = accountViewModel,
|
||||
@ -149,11 +166,6 @@ fun RenderRelay(
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val ripple = rememberRipple(bounded = false, radius = Size15dp)
|
||||
|
||||
val automaticallyShowProfilePicture =
|
||||
remember {
|
||||
accountViewModel.settings.showProfilePictures.value
|
||||
}
|
||||
|
||||
val clickableModifier =
|
||||
remember(relay) {
|
||||
Modifier
|
||||
@ -166,7 +178,9 @@ fun RenderRelay(
|
||||
onClick = {
|
||||
accountViewModel.retrieveRelayDocument(
|
||||
relay.url,
|
||||
onInfo = { relayInfo = it },
|
||||
onInfo = {
|
||||
openRelayDialog = true
|
||||
},
|
||||
onError = { url, errorCode, exceptionMessage ->
|
||||
val msg =
|
||||
when (errorCode) {
|
||||
@ -213,14 +227,18 @@ fun RenderRelay(
|
||||
modifier = clickableModifier,
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
RenderRelayIcon(relay.displayUrl, relay.favIcon, automaticallyShowProfilePicture)
|
||||
RenderRelayIcon(
|
||||
displayUrl = relay.displayUrl,
|
||||
iconUrl = relayInfo?.icon ?: relay.favIcon,
|
||||
loadProfilePicture = accountViewModel.settings.showProfilePictures.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RenderRelayIcon(
|
||||
displayUrl: String,
|
||||
iconUrl: String,
|
||||
iconUrl: String?,
|
||||
loadProfilePicture: Boolean,
|
||||
iconModifier: Modifier = MaterialTheme.colorScheme.relayIconModifier,
|
||||
) {
|
||||
|
@ -774,4 +774,6 @@
|
||||
<string name="this_version_brought_to_you_by">This version was brought to you by:</string>
|
||||
<string name="version_name">Version %1$s</string>
|
||||
<string name="thank_you">Thank you!</string>
|
||||
<string name="max_limit">Max Limit</string>
|
||||
<string name="restricted_writes">Restricted Writes</string>
|
||||
</resources>
|
||||
|
@ -29,6 +29,7 @@ class Nip11RelayInformation(
|
||||
val id: String?,
|
||||
val name: String?,
|
||||
val description: String?,
|
||||
val icon: String?,
|
||||
val pubkey: String?,
|
||||
val contact: String?,
|
||||
val supported_nips: List<Int>?,
|
||||
@ -41,7 +42,9 @@ class Nip11RelayInformation(
|
||||
val tags: List<String>?,
|
||||
val posting_policy: String?,
|
||||
val payments_url: String?,
|
||||
val retention: List<RelayInformationRetentionData>?,
|
||||
val fees: RelayInformationFees?,
|
||||
val nip50: List<String>?,
|
||||
) {
|
||||
companion object {
|
||||
val mapper =
|
||||
@ -63,7 +66,6 @@ class RelayInformationFees(
|
||||
val admission: List<RelayInformationFee>?,
|
||||
val subscription: List<RelayInformationFee>?,
|
||||
val publication: List<RelayInformationFee>?,
|
||||
val retention: List<RelayInformationFee>?,
|
||||
)
|
||||
|
||||
class RelayInformationLimitation(
|
||||
@ -78,4 +80,13 @@ class RelayInformationLimitation(
|
||||
val min_pow_difficulty: Int?,
|
||||
val auth_required: Boolean?,
|
||||
val payment_required: Boolean?,
|
||||
val restricted_writes: Boolean?,
|
||||
val created_at_lower_limit: Int?,
|
||||
val created_at_upper_limit: Int?,
|
||||
)
|
||||
|
||||
class RelayInformationRetentionData(
|
||||
val kinds: ArrayList<Int>,
|
||||
val tiem: Int?,
|
||||
val count: Int?,
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user