refactor(screens): NIP-11 cache to commonMain; shared stringRes and painterRes in more screens

Shared exits that block the most screens, cut before the next screen wave:
- Nip11CachedRetriever and RetrieveResult move to commons/commonMain over a Nip11Fetcher
  interface; the OkHttp Nip11Retriever implements it in jvmAndroid, and a jvmAndroid
  Nip11CachedRetriever(okHttpClient) function keeps existing call sites. The error enum is
  now Nip11ErrorCode.
- LocalCacheHost exposes the app's nip11Cache (an offline one by default), so the 26
  Amethyst.instance.nip11Cache reads, loadRelayInfo and WarmNip11 among them, go through
  LocalCache.appHost instead of the Android application.
- 21 app files switch from the app's stringRes/pluralStringRes aliases to the commonsUI
  ones; the files that still pass Android R.string ids keep the app overloads.
- ic_compose, github, ic_qrcode, relays, original and ic_tor are now also Compose
  resources, and painterRes(R.drawable.x) calls use the shared painterRes. The Android
  copies stay where the manifest, shortcuts or other R.drawable references still need them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7FuNBSKiyVecARSoE4B9P
This commit is contained in:
Claude
2026-09-28 20:41:03 +00:00
parent c2f6322c7b
commit 8dcd1753cc
88 changed files with 250 additions and 171 deletions
@@ -59,6 +59,8 @@ class AmethystLocalCacheHost(
override fun relayInfo(relay: NormalizedRelayUrl): Nip11RelayInformation = modules.nip11Cache.getFromCache(relay)
override val nip11Cache get() = modules.nip11Cache
// The zap path's LNURL cache is a quartz-side singleton the outbound-zap resolver fills.
override fun lnurlEndpoint(lnurlpUrl: String): LnurlEndpointInfo? = LnurlEndpointCache.get(lnurlpUrl)
@@ -24,7 +24,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.produceState
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.Nip11CachedRetriever
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.nip11RelayInfo.Nip11RelayInformation
@@ -33,7 +33,7 @@ import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
@Composable
fun loadRelayInfo(relay: NormalizedRelayUrl): State<Nip11RelayInformation> = loadRelayInfo(relay, Amethyst.instance.nip11Cache)
fun loadRelayInfo(relay: NormalizedRelayUrl): State<Nip11RelayInformation> = loadRelayInfo(relay, LocalCache.appHost.nip11Cache)
/**
* Eagerly warms the NIP-11 cache for a whole set of [relays] **in parallel** (each fetch on its own
@@ -48,7 +48,7 @@ fun WarmNip11(
relays: Collection<NormalizedRelayUrl>,
onEachLoaded: () -> Unit = {},
) {
val cache = Amethyst.instance.nip11Cache
val cache = LocalCache.appHost.nip11Cache
LaunchedEffect(relays) {
coroutineScope {
relays.forEach { relay ->
@@ -63,7 +63,6 @@ import coil3.request.ImageRequest
import coil3.size.Size
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache
@@ -80,6 +79,7 @@ import com.vitorpamplona.amethyst.commons.resources.media_actions_dialog_title
import com.vitorpamplona.amethyst.commons.resources.media_added
import com.vitorpamplona.amethyst.commons.resources.media_added_to_profile_gallery
import com.vitorpamplona.amethyst.commons.resources.media_download_has_started_toast
import com.vitorpamplona.amethyst.commons.resources.original
import com.vitorpamplona.amethyst.commons.resources.share_image
import com.vitorpamplona.amethyst.commons.resources.share_video
import com.vitorpamplona.amethyst.commons.resources.unable_to_share_image
@@ -113,6 +113,7 @@ import com.vitorpamplona.amethyst.commons.ui.components.util.setText
import com.vitorpamplona.amethyst.commons.ui.loadStringRes
import com.vitorpamplona.amethyst.commons.ui.note.BlankNote
import com.vitorpamplona.amethyst.commons.ui.note.DownloadForOfflineIcon
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size30Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size40dp
@@ -125,7 +126,6 @@ import com.vitorpamplona.amethyst.service.images.BlossomFetcher
import com.vitorpamplona.amethyst.service.playback.composable.VideoView
import com.vitorpamplona.amethyst.ui.components.pdf.PdfPreviewCard
import com.vitorpamplona.amethyst.ui.components.pdf.PdfViewerDialog
import com.vitorpamplona.amethyst.ui.painterRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.saveMediaToGallery
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
import com.vitorpamplona.quartz.nip19Bech32.Nip19Parser
@@ -1066,7 +1066,7 @@ private fun HashVerificationSymbol(verifiedHash: Boolean) {
},
) {
Icon(
painter = painterRes(R.drawable.original, 1),
painter = painterRes(Res.drawable.original, 1),
contentDescription = stringRes(id = Res.string.hash_verification_passed),
modifier = Size30Modifier,
tint = MaterialTheme.colorScheme.primary,
@@ -32,19 +32,19 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.tooling.preview.Preview
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.github
import com.vitorpamplona.amethyst.commons.resources.profile_banner
import com.vitorpamplona.amethyst.commons.ui.components.NewItemsBubble
import com.vitorpamplona.amethyst.commons.ui.layouts.ChatHeaderLayout
import com.vitorpamplona.amethyst.commons.ui.layouts.listItem.SlimListItem
import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgo
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness
import com.vitorpamplona.amethyst.commons.ui.theme.Height4dpModifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn
import com.vitorpamplona.amethyst.ui.painterRes
import com.vitorpamplona.quartz.utils.TimeUtils
private const val PREVIEW_AUTHOR = "This is my author"
@@ -58,7 +58,7 @@ fun ChannelNamePreview() {
ChatHeaderLayout(
channelPicture = {
Image(
painter = painterRes(R.drawable.github, 1),
painter = painterRes(Res.drawable.github, 1),
contentDescription = stringRes(id = Res.string.profile_banner),
contentScale = ContentScale.FillWidth,
)
@@ -92,7 +92,7 @@ fun ChannelNamePreview() {
},
leadingContent = {
Image(
painter = painterRes(R.drawable.github, 2),
painter = painterRes(Res.drawable.github, 2),
contentDescription = stringRes(id = Res.string.profile_banner),
contentScale = ContentScale.FillWidth,
modifier = Size55Modifier,
@@ -117,7 +117,7 @@ fun ChannelNamePreview() {
},
leadingContent = {
Image(
painter = painterRes(R.drawable.github, 2),
painter = painterRes(Res.drawable.github, 2),
contentDescription = stringRes(id = Res.string.profile_banner),
contentScale = ContentScale.FillWidth,
modifier = Size55Modifier,
@@ -33,12 +33,13 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.sp
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.github
import com.vitorpamplona.amethyst.commons.resources.profile_banner
import com.vitorpamplona.amethyst.commons.ui.layouts.LeftPictureLayout
import com.vitorpamplona.amethyst.commons.ui.note.LikeIcon
import com.vitorpamplona.amethyst.commons.ui.note.ZappedIcon
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.QuoteBorder
import com.vitorpamplona.amethyst.commons.ui.theme.Size16Modifier
@@ -47,7 +48,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer
import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
import com.vitorpamplona.amethyst.ui.note.TextCount
import com.vitorpamplona.amethyst.ui.painterRes
@Composable
@Preview
@@ -60,7 +60,7 @@ fun LeftPictureLayoutPreviewCard() {
LeftPictureLayout(
onImage = {
Image(
painter = painterRes(R.drawable.github, 3),
painter = painterRes(Res.drawable.github, 3),
contentDescription = stringRes(id = Res.string.profile_banner),
contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxSize().clip(QuoteBorder),
@@ -32,19 +32,19 @@ import androidx.compose.ui.Alignment.Companion.CenterVertically
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.tooling.preview.Preview
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.github
import com.vitorpamplona.amethyst.commons.resources.profile_banner
import com.vitorpamplona.amethyst.commons.ui.components.NewItemsBubble
import com.vitorpamplona.amethyst.commons.ui.layouts.ChatHeaderLayout
import com.vitorpamplona.amethyst.commons.ui.layouts.listItem.SlimListItem
import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgo
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness
import com.vitorpamplona.amethyst.commons.ui.theme.Height4dpModifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn
import com.vitorpamplona.amethyst.ui.painterRes
import com.vitorpamplona.quartz.utils.TimeUtils
private const val PREVIEW_AUTHOR = "This is my author"
@@ -58,7 +58,7 @@ fun ChannelNamePreview() {
ChatHeaderLayout(
channelPicture = {
Image(
painter = painterRes(R.drawable.github, 1),
painter = painterRes(Res.drawable.github, 1),
contentDescription = stringRes(id = Res.string.profile_banner),
contentScale = ContentScale.FillWidth,
)
@@ -92,7 +92,7 @@ fun ChannelNamePreview() {
},
leadingContent = {
Image(
painter = painterRes(R.drawable.github, 2),
painter = painterRes(Res.drawable.github, 2),
contentDescription = stringRes(id = Res.string.profile_banner),
contentScale = ContentScale.FillWidth,
modifier = Size55Modifier,
@@ -118,7 +118,7 @@ fun ChannelNamePreview() {
},
leadingContent = {
Image(
painter = painterRes(R.drawable.github, 2),
painter = painterRes(Res.drawable.github, 2),
contentDescription = stringRes(id = Res.string.profile_banner),
contentScale = ContentScale.FillWidth,
modifier = Size55Modifier,
@@ -90,7 +90,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import coil3.compose.AsyncImage
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.BuildConfig
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
@@ -113,12 +112,14 @@ import com.vitorpamplona.amethyst.commons.resources.drawer_section_feeds
import com.vitorpamplona.amethyst.commons.resources.drawer_section_you
import com.vitorpamplona.amethyst.commons.resources.followers
import com.vitorpamplona.amethyst.commons.resources.following
import com.vitorpamplona.amethyst.commons.resources.ic_qrcode
import com.vitorpamplona.amethyst.commons.resources.longs
import com.vitorpamplona.amethyst.commons.resources.pictures
import com.vitorpamplona.amethyst.commons.resources.profile
import com.vitorpamplona.amethyst.commons.resources.profile_banner
import com.vitorpamplona.amethyst.commons.resources.profile_image
import com.vitorpamplona.amethyst.commons.resources.relay_setup
import com.vitorpamplona.amethyst.commons.resources.relays
import com.vitorpamplona.amethyst.commons.resources.route_chess
import com.vitorpamplona.amethyst.commons.resources.share_hls_video
import com.vitorpamplona.amethyst.commons.resources.show_npub_as_a_qr_code
@@ -1006,7 +1007,7 @@ fun IconRowRelays(
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterRes(R.drawable.relays, 4),
painter = painterRes(Res.drawable.relays, 4),
contentDescription = stringRes(Res.string.relay_setup),
modifier = Size22Modifier,
tint = MaterialTheme.colorScheme.onSurface,
@@ -1103,7 +1104,7 @@ fun BottomContent(
},
) {
Icon(
painter = painterRes(R.drawable.ic_qrcode, 2),
painter = painterRes(Res.drawable.ic_qrcode, 2),
contentDescription = stringRes(id = Res.string.show_npub_as_a_qr_code),
modifier = Size24Modifier,
tint = MaterialTheme.colorScheme.primary,
@@ -96,8 +96,8 @@ import com.vitorpamplona.amethyst.commons.resources.backup_conflict_title
import com.vitorpamplona.amethyst.commons.resources.backup_review_changed_by_other_app
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.note.timeAgoNoDot
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.concord.cord02Community.ConcordCommunityListDiff
import com.vitorpamplona.quartz.experimental.ephemChat.list.EphemeralChatListDiff
import com.vitorpamplona.quartz.nip01Core.diff.ContentChange
@@ -118,11 +118,11 @@ import com.vitorpamplona.amethyst.commons.ui.note.LoadPublicChatChannel
import com.vitorpamplona.amethyst.commons.ui.note.LoadUser
import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
import com.vitorpamplona.amethyst.commons.util.toShortDisplay
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.concord.cord02Community.ConcordCommunityListDiff
import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId
import com.vitorpamplona.quartz.experimental.ephemChat.list.EphemeralChatListDiff
@@ -100,11 +100,11 @@ import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose
import com.vitorpamplona.amethyst.commons.ui.note.UserPicture
import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay
import com.vitorpamplona.amethyst.commons.ui.note.timeAgoNoDot
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
import com.vitorpamplona.amethyst.commons.util.toShortDisplay
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.experimental.ephemChat.list.EphemeralChatListDiff
import com.vitorpamplona.quartz.nip01Core.diff.ContentChange
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataDiff
@@ -30,14 +30,14 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.ic_compose
import com.vitorpamplona.amethyst.commons.resources.new_badge
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.painterRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.post.NewBadgeDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.post.NewBadgeModel
@@ -61,7 +61,7 @@ fun NewBadgeButton(accountViewModel: AccountViewModel) {
containerColor = MaterialTheme.colorScheme.primary,
) {
Icon(
painter = painterRes(R.drawable.ic_compose, 5),
painter = painterRes(Res.drawable.ic_compose, 5),
contentDescription = stringRes(id = Res.string.new_badge),
modifier = Size26Modifier,
tint = MaterialTheme.colorScheme.onPrimary,
@@ -51,6 +51,7 @@ import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.cordn_composer_hint
import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList
import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.text.MentionPreservingInputTransformation
import com.vitorpamplona.amethyst.commons.ui.text.currentWord
import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord
@@ -66,7 +67,6 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
import com.vitorpamplona.amethyst.ui.actions.uploads.VoiceMessagePreview
import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.nipA0VoiceMessages.AudioMeta
/**
@@ -122,12 +122,12 @@ import com.vitorpamplona.amethyst.commons.ui.components.EmptyState
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.note.UserPicture
import com.vitorpamplona.amethyst.commons.ui.note.timeAgoNoDot
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.pluralStringRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.CoordinatorIdentityRow
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.coordinatorDisplayName
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.cordn.spec01GroupMetadata.CordnGroupMetadata
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -80,12 +80,12 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackBu
import com.vitorpamplona.amethyst.commons.ui.note.UserPicture
import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList
import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightChat
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.commons.viewmodels.CordnGroupDraft
import com.vitorpamplona.amethyst.ui.pluralStringRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.nip01Core.core.HexKey
/**
@@ -110,6 +110,8 @@ import com.vitorpamplona.amethyst.commons.ui.loadStringRes
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.note.NonClickableUserPictures
import com.vitorpamplona.amethyst.commons.ui.note.UserPicture
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
@@ -121,11 +123,9 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
import com.vitorpamplona.amethyst.ui.actions.uploads.VoiceMessageRecorder
import com.vitorpamplona.amethyst.ui.components.ZoomableContentView
import com.vitorpamplona.amethyst.ui.note.types.RenderAudioWaveformPlayer
import com.vitorpamplona.amethyst.ui.pluralStringRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadState
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.cordn.appEncryptedMedia.CordnBlobUpload
import com.vitorpamplona.quartz.cordn.appEncryptedMedia.CordnMediaAttachment
import com.vitorpamplona.quartz.cordn.appEncryptedMedia.CordnMediaCipher
@@ -130,16 +130,16 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.note.UserPicture
import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList
import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightChat
import com.vitorpamplona.amethyst.commons.util.toShortDisplay
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.pluralStringRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.QrCodeDrawer
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SectionCollapse
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SectionExpand
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.CoordinatorIdentityRow
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.cordn.spec00Coordinator.JoinRequest
import com.vitorpamplona.quartz.cordn.spec01GroupMetadata.CordnGroupMetadata
import com.vitorpamplona.quartz.nip01Core.core.HexKey
@@ -63,13 +63,13 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_groups_title
import com.vitorpamplona.amethyst.commons.ui.components.EmptyState
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar
import com.vitorpamplona.amethyst.ui.pluralStringRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.CordnGroupRoomCompose
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.CoordinatorIdentityRow
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import kotlinx.coroutines.flow.MutableStateFlow
@@ -77,11 +77,11 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_via
import com.vitorpamplona.amethyst.commons.ui.components.EmptyState
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.note.UserPicture
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.CoordinatorIdentityRow
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.coordinatorDisplayName
import com.vitorpamplona.amethyst.ui.stringRes
import kotlinx.coroutines.launch
import org.jetbrains.compose.resources.pluralStringResource
@@ -99,6 +99,7 @@ import com.vitorpamplona.amethyst.commons.ui.note.QuickActionAlertDialog
import com.vitorpamplona.amethyst.commons.ui.note.UserPicture
import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgoStyle
import com.vitorpamplona.amethyst.commons.ui.note.elements.ToggleableTimeAgoText
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Font12SP
import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp
import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer
@@ -116,7 +117,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.TileRow
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.authorNameColorFor
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.coordinatorDisplayName
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.cordn.appEncryptedMedia.CordnMediaTag
import com.vitorpamplona.quartz.cordn.spec02Envelopes.CordnAnnotationIndex
import com.vitorpamplona.quartz.cordn.spec02Envelopes.CordnDeliveredMessage
@@ -45,7 +45,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel
import com.vitorpamplona.amethyst.commons.resources.Res
@@ -238,7 +238,7 @@ private fun ChannelMetadataScaffold(
BasicRelaySetupInfoDialog(
item,
onDelete = { postViewModel.deleteHomeRelay(item) },
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = HorzHalfVertPadding,
accountViewModel = accountViewModel,
nav = nav,
@@ -47,7 +47,7 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.model.navigation.Route
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.relay_group_browse_description
@@ -170,7 +170,7 @@ fun RelayGroupBrowseScreen(
relaySuggestions = relaySuggestions,
onSelect = { relay -> open(relay.url) },
modifier = HalfHorzPadding,
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
accountViewModel = accountViewModel,
nav = nav,
)
@@ -201,7 +201,7 @@ fun RelayGroupChannelListScreen(
// Warm the relay's NIP-11 so we can tell its genuine (relay-signed) groups from stray
// user-published 39000s that a non-NIP-29 relay may also be storing. Re-keyed on trust so a move
// to clearnet re-fetches over the new transport instead of serving the cached over-Tor failure.
val nip11Cache = Amethyst.instance.nip11Cache
val nip11Cache = LocalCache.appHost.nip11Cache
val relayInfo by produceState(nip11Cache.getFromCache(relay), relay, isTrusted) {
if (isTrusted) nip11Cache.invalidate(relay)
nip11Cache.loadRelayInfo(relay, onInfo = { value = it }, onError = { _, _, _ -> })
@@ -66,9 +66,9 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import coil3.compose.AsyncImage
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.model.navigation.Route
import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel
import com.vitorpamplona.amethyst.commons.resources.Res
@@ -145,7 +145,7 @@ fun RelayGroupCreateScreen(
// on the relay advertising NIP-29 in its NIP-11 `supported_nips`. Tri-state: null = still checking,
// false = confirmed unsupported (or unreachable), true = advertised.
val nip29Support by produceState<Boolean?>(initialValue = null, relay) {
Amethyst.instance.nip11Cache.loadRelayInfo(
LocalCache.appHost.nip11Cache.loadRelayInfo(
relay = relay,
onInfo = { info -> value = info.supported_nips?.any { it == "29" } ?: false },
onError = { _, _, _ -> value = false },
@@ -217,7 +217,7 @@ private fun RelayGroupMetadataScaffold(
// NIP-29 §Subgroups relay support detection: `"nip29": { "subgroups": true }` in the NIP-11.
val subgroupsSupported by produceState(initialValue = false, viewModel.relay) {
val relay = viewModel.relay ?: return@produceState
Amethyst.instance.nip11Cache.loadRelayInfo(
LocalCache.appHost.nip11Cache.loadRelayInfo(
relay = relay,
onInfo = { info -> value = info.nip29?.subgroups == true },
onError = { _, _, _ -> value = false },
@@ -25,18 +25,18 @@ import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.model.Note
import com.vitorpamplona.amethyst.commons.model.navigation.Route
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.ic_compose
import com.vitorpamplona.amethyst.commons.resources.new_community_note
import com.vitorpamplona.amethyst.commons.ui.components.LoadNote
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.painterRes
@Composable
fun NewCommunityNoteButton(
@@ -68,7 +68,7 @@ fun NewCommunityNoteButton(
containerColor = MaterialTheme.colorScheme.primary,
) {
Icon(
painter = painterRes(R.drawable.ic_compose, 2),
painter = painterRes(Res.drawable.ic_compose, 2),
contentDescription = stringRes(id = Res.string.new_community_note),
modifier = Size26Modifier,
tint = MaterialTheme.colorScheme.onPrimary,
@@ -66,7 +66,6 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import coil3.compose.AsyncImage
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.model.User
@@ -578,7 +577,7 @@ private fun RelaysSection(
loadRobohash = LocalDisplaySettings.current.loadRobohash,
onClick = {},
onDelete = { model.removeRelay(entry) },
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
accountViewModel = accountViewModel,
nav = nav,
)
@@ -75,6 +75,7 @@ import com.vitorpamplona.amethyst.commons.resources.favorite_notice_published
import com.vitorpamplona.amethyst.commons.resources.favorite_notice_uploaded
import com.vitorpamplona.amethyst.commons.ui.loadStringRes
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.favorites.FavoriteAppLauncher
import com.vitorpamplona.amethyst.napplet.NappletNetworkRegistry
@@ -85,7 +86,6 @@ import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar
import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabChrome
import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabFactory
import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabHost
import com.vitorpamplona.amethyst.ui.stringRes
import kotlinx.coroutines.launch
import org.jetbrains.compose.resources.StringResource
@@ -25,16 +25,16 @@ import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.model.navigation.Route
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.ic_compose
import com.vitorpamplona.amethyst.commons.resources.new_community_note
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.painterRes
@Composable
fun NewGeoPostButton(
@@ -51,7 +51,7 @@ fun NewGeoPostButton(
containerColor = MaterialTheme.colorScheme.primary,
) {
Icon(
painter = painterRes(R.drawable.ic_compose, 1),
painter = painterRes(Res.drawable.ic_compose, 1),
contentDescription = stringRes(id = Res.string.new_community_note),
modifier = Size26Modifier,
tint = MaterialTheme.colorScheme.onPrimary,
@@ -25,16 +25,16 @@ import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.model.navigation.Route
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.ic_compose
import com.vitorpamplona.amethyst.commons.resources.new_community_note
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.painterRes
@Composable
fun NewHashtagPostButton(
@@ -51,7 +51,7 @@ fun NewHashtagPostButton(
containerColor = MaterialTheme.colorScheme.primary,
) {
Icon(
painter = painterRes(R.drawable.ic_compose, 3),
painter = painterRes(Res.drawable.ic_compose, 3),
contentDescription = stringRes(id = Res.string.new_community_note),
modifier = Size26Modifier,
tint = MaterialTheme.colorScheme.onPrimary,
@@ -25,15 +25,15 @@ import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.model.navigation.Route
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.ic_compose
import com.vitorpamplona.amethyst.commons.resources.new_highlight_title
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier
import com.vitorpamplona.amethyst.ui.painterRes
@Composable
fun NewHighlightButton(nav: INav) {
@@ -46,7 +46,7 @@ fun NewHighlightButton(nav: INav) {
containerColor = MaterialTheme.colorScheme.primary,
) {
Icon(
painter = painterRes(R.drawable.ic_compose, 4),
painter = painterRes(Res.drawable.ic_compose, 4),
contentDescription = stringRes(Res.string.new_highlight_title),
modifier = Size26Modifier,
tint = MaterialTheme.colorScheme.onPrimary,
@@ -31,17 +31,17 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.model.navigation.Route
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.ic_compose
import com.vitorpamplona.amethyst.commons.resources.new_post
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow
import com.vitorpamplona.amethyst.ui.painterRes
@Preview
@Composable
@@ -64,7 +64,7 @@ fun NewNoteButton(nav: INav) {
containerColor = MaterialTheme.colorScheme.primary,
) {
Icon(
painter = painterRes(R.drawable.ic_compose, 4),
painter = painterRes(Res.drawable.ic_compose, 4),
contentDescription = stringRes(Res.string.new_post),
modifier = Size26Modifier,
tint = MaterialTheme.colorScheme.onPrimary,
@@ -42,15 +42,16 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.model.VideoPostKind
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.ic_compose
import com.vitorpamplona.amethyst.commons.resources.new_long_video
import com.vitorpamplona.amethyst.commons.resources.record_a_video
import com.vitorpamplona.amethyst.commons.resources.upload_image
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier
@@ -60,7 +61,6 @@ import com.vitorpamplona.amethyst.ui.actions.NewMediaView
import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelect
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideo
import com.vitorpamplona.amethyst.ui.painterRes
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.Dispatchers
@@ -193,7 +193,7 @@ fun NewLongVideoButton(
exit = fadeOut(),
) {
Icon(
painter = painterRes(R.drawable.ic_compose, 5),
painter = painterRes(Res.drawable.ic_compose, 5),
contentDescription = stringRes(id = Res.string.new_long_video),
modifier = Size26Modifier,
tint = MaterialTheme.colorScheme.onPrimary,
@@ -44,14 +44,15 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.ic_compose
import com.vitorpamplona.amethyst.commons.resources.new_picture
import com.vitorpamplona.amethyst.commons.resources.take_a_picture
import com.vitorpamplona.amethyst.commons.resources.upload_image
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier
@@ -62,7 +63,6 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelect
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
import com.vitorpamplona.amethyst.ui.actions.uploads.TakePicture
import com.vitorpamplona.amethyst.ui.actions.uploads.resolveSharedMedia
import com.vitorpamplona.amethyst.ui.painterRes
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.Dispatchers
@@ -206,7 +206,7 @@ fun NewPictureButton(
exit = fadeOut(),
) {
Icon(
painter = painterRes(R.drawable.ic_compose, 5),
painter = painterRes(Res.drawable.ic_compose, 5),
contentDescription = stringRes(id = Res.string.new_picture),
modifier = Size26Modifier,
tint = MaterialTheme.colorScheme.onPrimary,
@@ -25,15 +25,15 @@ import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.model.navigation.Route
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.ic_compose
import com.vitorpamplona.amethyst.commons.resources.new_poll
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier
import com.vitorpamplona.amethyst.ui.painterRes
@Composable
fun NewPollButton(nav: INav) {
@@ -44,7 +44,7 @@ fun NewPollButton(nav: INav) {
containerColor = MaterialTheme.colorScheme.primary,
) {
Icon(
painter = painterRes(R.drawable.ic_compose, 4),
painter = painterRes(Res.drawable.ic_compose, 4),
contentDescription = stringRes(id = Res.string.new_poll),
modifier = Size26Modifier,
tint = MaterialTheme.colorScheme.onPrimary,
@@ -60,6 +60,7 @@ import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.copy_nprofile_to_clipboard
import com.vitorpamplona.amethyst.commons.resources.copy_npub_to_clipboard
import com.vitorpamplona.amethyst.commons.resources.github
import com.vitorpamplona.amethyst.commons.resources.ic_qrcode
import com.vitorpamplona.amethyst.commons.resources.mastodon
import com.vitorpamplona.amethyst.commons.resources.show_nprofile_as_a_qr_code
import com.vitorpamplona.amethyst.commons.resources.telegram
@@ -69,6 +70,7 @@ import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextView
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.note.ObserveAndRenderNIP05VerifiedSymbol
import com.vitorpamplona.amethyst.commons.ui.note.lastSeenSentence
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size15Modifier
@@ -213,7 +215,7 @@ fun DrawAdditionalInfo(
onClick = { nav.nav(Route.QRDisplay(baseUser.pubkeyHex)) },
) {
Icon(
painter = painterRes(R.drawable.ic_qrcode, 1),
painter = painterRes(Res.drawable.ic_qrcode, 1),
contentDescription = stringRes(id = Res.string.show_nprofile_as_a_qr_code),
modifier = Size15Modifier,
tint = MaterialTheme.colorScheme.placeholderText,
@@ -25,16 +25,16 @@ import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.model.navigation.Route
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.ic_compose
import com.vitorpamplona.amethyst.commons.resources.new_community_note
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.painterRes
@Composable
fun NewRelayNoteButton(
@@ -50,7 +50,7 @@ fun NewRelayNoteButton(
containerColor = MaterialTheme.colorScheme.primary,
) {
Icon(
painter = painterRes(R.drawable.ic_compose, 3),
painter = painterRes(Res.drawable.ic_compose, 3),
contentDescription = stringRes(id = Res.string.new_community_note),
modifier = Size26Modifier,
tint = MaterialTheme.colorScheme.onPrimary,
@@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
@@ -80,7 +80,7 @@ fun LazyListScope.renderBlockedItems(
BasicRelaySetupInfoDialog(
item,
onDelete = { postViewModel.deleteRelay(item) },
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = HorzHalfVertPadding,
index = index,
dragState = dragState,
@@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
@@ -80,7 +80,7 @@ fun LazyListScope.renderBroadcastItems(
BasicRelaySetupInfoDialog(
item,
onDelete = { postViewModel.deleteRelay(item) },
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = HorzHalfVertPadding,
index = index,
dragState = dragState,
@@ -24,6 +24,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.Account
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.ui.CountFilter
import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
import com.vitorpamplona.amethyst.commons.util.replace
@@ -77,7 +78,7 @@ abstract class BasicRelaySetupInfoModel : ViewModel() {
fun loadRelayDocuments() {
viewModelScope.launch(Dispatchers.IO) {
_relays.value.forEach { item ->
Amethyst.instance.nip11Cache.loadRelayInfo(
LocalCache.appHost.nip11Cache.loadRelayInfo(
relay = item.relay,
onInfo = {
togglePaidRelay(item, it.limitation?.payment_required ?: false)
@@ -36,18 +36,18 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.ic_tor
import com.vitorpamplona.amethyst.commons.resources.paid_relay
import com.vitorpamplona.amethyst.commons.resources.remove
import com.vitorpamplona.amethyst.commons.resources.tor_relay
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.LightRedColor
import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor
import com.vitorpamplona.amethyst.ui.painterRes
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl
import kotlinx.coroutines.launch
@@ -92,7 +92,7 @@ fun RelayNameAndRemoveButton(
if (item.forcesTor) {
Icon(
painter = painterRes(R.drawable.ic_tor, 2),
painter = painterRes(Res.drawable.ic_tor, 2),
contentDescription = stringRes(id = Res.string.tor_relay),
modifier =
Modifier
@@ -44,7 +44,7 @@ import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.Nip11CachedRetriever
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.add
@@ -137,7 +137,7 @@ fun RelayUrlEditField(
) {
RelayUrlEditField(
onNewRelay = onNewRelay,
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = modifier,
accountViewModel = accountViewModel,
nav = nav,
@@ -36,7 +36,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.model.navigation.Route
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.active_subs_title
@@ -98,7 +98,7 @@ fun LazyListScope.renderConnectedItems(
BasicRelaySetupInfoDialog(
item,
onDelete = null,
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = HorzHalfVertPadding,
accountViewModel = accountViewModel,
nav = nav,
@@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
@@ -83,7 +83,7 @@ fun LazyListScope.renderDMItems(
BasicRelaySetupInfoDialog(
item,
onDelete = { postViewModel.deleteRelay(item) },
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = HorzHalfVertPadding,
countResult = countResults[item.relay],
index = index,
@@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
@@ -80,7 +80,7 @@ fun LazyListScope.renderRelayFeedsItems(
BasicRelaySetupInfoDialog(
item,
onDelete = { postViewModel.deleteRelay(item) },
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = HorzHalfVertPadding,
index = index,
dragState = dragState,
@@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
@@ -83,7 +83,7 @@ fun LazyListScope.renderIndexerItems(
BasicRelaySetupInfoDialog(
item,
onDelete = { postViewModel.deleteRelay(item) },
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = HorzHalfVertPadding,
countResult = countResults[item.relay],
index = index,
@@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
@@ -83,7 +83,7 @@ fun LazyListScope.renderKeyPackageItems(
BasicRelaySetupInfoDialog(
item,
onDelete = { postViewModel.deleteRelay(item) },
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = HorzHalfVertPadding,
countResult = countResults[item.relay],
index = index,
@@ -30,7 +30,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
import com.vitorpamplona.amethyst.commons.resources.Res
@@ -86,7 +86,7 @@ fun LazyListScope.renderLocalItems(
BasicRelaySetupInfoDialog(
item,
onDelete = { postViewModel.deleteRelay(item) },
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = HorzHalfVertPadding,
index = index,
dragState = dragState,
@@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
@@ -83,7 +83,7 @@ fun LazyListScope.renderPrivateOutboxItems(
BasicRelaySetupInfoDialog(
item,
onDelete = { postViewModel.deleteRelay(item) },
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = HorzHalfVertPadding,
countResult = countResults[item.relay],
index = index,
@@ -59,9 +59,9 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.nip43RelayMembers.ui.RelayRoleChips
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.relay_members_count
@@ -124,7 +124,7 @@ fun RelayMembersScreen(
LaunchedEffect(normalizedRelayUrl) {
launch(Dispatchers.IO) {
var relaySelf: HexKey? = null
Amethyst.instance.nip11Cache.loadRelayInfo(
LocalCache.appHost.nip11Cache.loadRelayInfo(
relay = normalizedRelayUrl,
onInfo = { relaySelf = it.self },
onError = { _, _, _ -> },
@@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
@@ -142,7 +142,7 @@ fun LazyListScope.renderNip65HomeItems(
BasicRelaySetupInfoDialog(
item,
onDelete = { postViewModel.deleteHomeRelay(item) },
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = HorzHalfVertPadding,
countResult = countResults[item.relay],
index = index,
@@ -175,7 +175,7 @@ fun LazyListScope.renderNip65NotifItems(
BasicRelaySetupInfoDialog(
item,
onDelete = { postViewModel.deleteNotifRelay(item) },
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = HorzHalfVertPadding,
countResult = countResults[item.relay],
index = index,
@@ -25,6 +25,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.Account
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.events_from_you
@@ -104,7 +105,7 @@ class Nip65RelayListViewModel : ViewModel() {
fun loadRelayDocuments() {
viewModelScope.launch(Dispatchers.IO) {
_homeRelays.value.forEach { item ->
Amethyst.instance.nip11Cache.loadRelayInfo(
LocalCache.appHost.nip11Cache.loadRelayInfo(
relay = item.relay,
onInfo = {
toggleHomePaidRelay(item, it.limitation?.payment_required ?: false)
@@ -114,7 +115,7 @@ class Nip65RelayListViewModel : ViewModel() {
}
_notificationRelays.value.forEach { item ->
Amethyst.instance.nip11Cache.loadRelayInfo(
LocalCache.appHost.nip11Cache.loadRelayInfo(
relay = item.relay,
onInfo = {
toggleNotifPaidRelay(item, it.limitation?.payment_required ?: false)
@@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
@@ -83,7 +83,7 @@ fun LazyListScope.renderProxyItems(
BasicRelaySetupInfoDialog(
item,
onDelete = { postViewModel.deleteRelay(item) },
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = HorzHalfVertPadding,
countResult = countResults[item.relay],
index = index,
@@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
@@ -83,7 +83,7 @@ fun LazyListScope.renderSearchItems(
BasicRelaySetupInfoDialog(
item,
onDelete = { postViewModel.deleteRelay(item) },
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = HorzHalfVertPadding,
countResult = countResults[item.relay],
index = index,
@@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
@@ -80,7 +80,7 @@ fun LazyListScope.renderTrustedItems(
BasicRelaySetupInfoDialog(
item,
onDelete = { postViewModel.deleteRelay(item) },
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = HorzHalfVertPadding,
index = index,
dragState = dragState,
@@ -65,9 +65,9 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.Nip11CachedRetriever
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.cancel
@@ -118,7 +118,7 @@ fun RequestToVanishScreen(
nav: INav,
) {
RequestToVanishScreen(
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
accountViewModel = accountViewModel,
nav = nav,
)
@@ -826,7 +826,7 @@ private fun DisplaySearchResults(
loadRobohash = LocalDisplaySettings.current.loadRobohash,
onClick = { nav.nav(Route.RelayInfo(relayInfo.relay.url)) },
onDelete = null,
nip11CachedRetriever = Amethyst.instance.nip11Cache,
nip11CachedRetriever = LocalCache.appHost.nip11Cache,
modifier = Modifier.padding(vertical = 5.dp, horizontal = 10.dp),
accountViewModel = accountViewModel,
nav = nav,
@@ -77,9 +77,9 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable_deta
import com.vitorpamplona.amethyst.commons.ui.components.EmptyState
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsSection
import com.vitorpamplona.amethyst.ui.stringRes
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -114,12 +114,12 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton
import com.vitorpamplona.amethyst.commons.ui.note.UserPicture
import com.vitorpamplona.amethyst.commons.ui.note.timeAgoNoDot
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.pluralStringRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.cordnGroup.CopyableKeyRow
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsSection
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.cordn.spec00Coordinator.CoordinatorServerInfo
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
import com.vitorpamplona.quartz.nip19Bech32.decodePublicKeyAsHexOrNull
@@ -55,13 +55,13 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_hub_title
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsControlRow
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsDivider
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsSection
import com.vitorpamplona.amethyst.ui.stringRes
import org.jetbrains.compose.resources.StringResource
/**
@@ -75,10 +75,10 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_withdraw_o
import com.vitorpamplona.amethyst.commons.ui.components.EmptyState
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.pluralStringRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsSection
import com.vitorpamplona.amethyst.ui.stringRes
import kotlinx.coroutines.launch
/**
@@ -69,10 +69,10 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_link_section_input
import com.vitorpamplona.amethyst.commons.resources.cordn_link_title
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.SimpleQrCodeScanner
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsSection
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import kotlinx.coroutines.launch
import org.jetbrains.compose.resources.stringResource
@@ -81,13 +81,13 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_migrate_title
import com.vitorpamplona.amethyst.commons.ui.components.EmptyState
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.model.cordn.AndroidCordnBlobStore
import com.vitorpamplona.amethyst.ui.pluralStringRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.QrCodeDrawer
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.SimpleQrCodeScanner
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsSection
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.cordn.appMultiDevice.CordnHandoffCode
import kotlinx.coroutines.launch
@@ -44,15 +44,16 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.model.VideoPostKind
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.ic_compose
import com.vitorpamplona.amethyst.commons.resources.new_short_video
import com.vitorpamplona.amethyst.commons.resources.record_a_video
import com.vitorpamplona.amethyst.commons.resources.upload_image
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier
@@ -63,7 +64,6 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelect
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideo
import com.vitorpamplona.amethyst.ui.actions.uploads.resolveSharedMedia
import com.vitorpamplona.amethyst.ui.painterRes
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.Dispatchers
@@ -208,7 +208,7 @@ fun NewShortVideoButton(
exit = fadeOut(),
) {
Icon(
painter = painterRes(R.drawable.ic_compose, 5),
painter = painterRes(Res.drawable.ic_compose, 5),
contentDescription = stringRes(id = Res.string.new_short_video),
modifier = Size26Modifier,
tint = MaterialTheme.colorScheme.onPrimary,
@@ -25,16 +25,16 @@ import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.model.navigation.Route
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.ic_compose
import com.vitorpamplona.amethyst.commons.resources.new_community_note
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.painterRes
@Composable
fun NewUrlPostButton(
@@ -51,7 +51,7 @@ fun NewUrlPostButton(
containerColor = MaterialTheme.colorScheme.primary,
) {
Icon(
painter = painterRes(R.drawable.ic_compose, 1),
painter = painterRes(Res.drawable.ic_compose, 1),
contentDescription = stringRes(id = Res.string.new_community_note),
modifier = Size26Modifier,
tint = MaterialTheme.colorScheme.onPrimary,
@@ -44,15 +44,16 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.ic_compose
import com.vitorpamplona.amethyst.commons.resources.new_media
import com.vitorpamplona.amethyst.commons.resources.record_a_video
import com.vitorpamplona.amethyst.commons.resources.take_a_picture
import com.vitorpamplona.amethyst.commons.resources.upload_image
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier
@@ -64,7 +65,6 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
import com.vitorpamplona.amethyst.ui.actions.uploads.TakePicture
import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideo
import com.vitorpamplona.amethyst.ui.actions.uploads.resolveSharedMedia
import com.vitorpamplona.amethyst.ui.painterRes
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.Dispatchers
@@ -242,7 +242,7 @@ fun NewVideoFeedButton(
exit = fadeOut(),
) {
Icon(
painter = painterRes(R.drawable.ic_compose, 5),
painter = painterRes(Res.drawable.ic_compose, 5),
contentDescription = stringRes(id = Res.string.new_media),
modifier = Size26Modifier,
tint = MaterialTheme.colorScheme.onPrimary,
@@ -50,12 +50,12 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.accessibility_scan_qr_code
import com.vitorpamplona.amethyst.commons.resources.back
import com.vitorpamplona.amethyst.commons.resources.ic_qrcode
import com.vitorpamplona.amethyst.commons.resources.paste_from_clipboard
import com.vitorpamplona.amethyst.commons.resources.wallet_add_clink_invalid
import com.vitorpamplona.amethyst.commons.resources.wallet_add_clink_title
@@ -66,10 +66,10 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_save
import com.vitorpamplona.amethyst.commons.ui.components.util.getText
import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size24Modifier
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.painterRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.SimpleQrCodeScanner
import kotlinx.coroutines.launch
@@ -161,7 +161,7 @@ fun AddClinkDebitWalletScreen(
// QR code scanner
IconButton(onClick = { qrScanning = true }) {
Icon(
painter = painterRes(R.drawable.ic_qrcode, 3),
painter = painterRes(Res.drawable.ic_qrcode, 3),
contentDescription = stringRes(id = Res.string.accessibility_scan_qr_code),
modifier = Modifier.size(24.dp),
tint = MaterialTheme.colorScheme.primary,
@@ -52,7 +52,6 @@ import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.resources.Res
@@ -60,6 +59,7 @@ import com.vitorpamplona.amethyst.commons.resources.accessibility_scan_qr_code
import com.vitorpamplona.amethyst.commons.resources.back
import com.vitorpamplona.amethyst.commons.resources.couldnt_find_nwc_wallets
import com.vitorpamplona.amethyst.commons.resources.couldnt_find_nwc_wallets_description
import com.vitorpamplona.amethyst.commons.resources.ic_qrcode
import com.vitorpamplona.amethyst.commons.resources.paste_from_clipboard
import com.vitorpamplona.amethyst.commons.resources.wallet_add_nwc_title
import com.vitorpamplona.amethyst.commons.resources.wallet_connect_connect_app
@@ -70,12 +70,12 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_save
import com.vitorpamplona.amethyst.commons.ui.components.util.getText
import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder
import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer
import com.vitorpamplona.amethyst.commons.ui.theme.Size24Modifier
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.ui.painterRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.SimpleQrCodeScanner
import com.vitorpamplona.quartz.nip47WalletConnect.Nip47DeepLink
import com.vitorpamplona.quartz.nip47WalletConnect.Nip47WalletConnect
@@ -198,7 +198,7 @@ fun AddNwcWalletScreen(
// QR code scanner
IconButton(onClick = { qrScanning = true }) {
Icon(
painter = painterRes(R.drawable.ic_qrcode, 3),
painter = painterRes(Res.drawable.ic_qrcode, 3),
contentDescription = stringRes(id = Res.string.accessibility_scan_qr_code),
modifier = Modifier.size(24.dp),
tint = MaterialTheme.colorScheme.primary,
@@ -44,17 +44,17 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.hide_password
import com.vitorpamplona.amethyst.commons.resources.ic_qrcode
import com.vitorpamplona.amethyst.commons.resources.login_with_qr_code
import com.vitorpamplona.amethyst.commons.resources.nsec_npub_hex_private_key
import com.vitorpamplona.amethyst.commons.resources.show_password
import com.vitorpamplona.amethyst.commons.ui.painterRes
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
import com.vitorpamplona.amethyst.ui.painterRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.SimpleQrCodeScanner
@Composable
@@ -113,7 +113,7 @@ fun KeyTextField(
}
IconButton(onClick = { dialogOpen = true }) {
Icon(
painter = painterRes(R.drawable.ic_qrcode, 5),
painter = painterRes(Res.drawable.ic_qrcode, 5),
contentDescription = stringRes(Res.string.login_with_qr_code),
modifier = Modifier.size(24.dp),
tint = MaterialTheme.colorScheme.primary,
@@ -87,7 +87,7 @@ class BuzzDmNotificationResolutionTest {
)
// Attach a 40002 by consuming it (which materializes the group channel) and then set its 39000
// metadata directly — the real 39000 consume gates on Amethyst.instance.nip11Cache, which isn't
// metadata directly — the real 39000 consume gates on LocalCache.appHost.nip11Cache, which isn't
// available in a plain JVM test (see BuzzWorkspaceChannelTest). We still drive the real resolver.
private fun consumeMessageInto(
channelId: String,
@@ -20,6 +20,8 @@
*/
package com.vitorpamplona.amethyst.commons.model.cache
import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.Nip11CachedRetriever
import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.Nip11Fetcher
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStats
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -64,6 +66,12 @@ interface LocalCacheHost {
*/
val nip95Blobs: Nip95BlobStore?
/**
* Relays' NIP-11 documents, shared by the cache (relay `self` keys) and the screens that show
* relay details. The default fetches nothing.
*/
val nip11Cache: Nip11CachedRetriever get() = OfflineNip11Cache
/** Per-relay counters the anti-spam filter reports duplicate events to. */
val relayStats: RelayStats?
@@ -104,3 +112,5 @@ interface LocalCacheHost {
override val relayStats: RelayStats? = null
}
}
private val OfflineNip11Cache = Nip11CachedRetriever(Nip11Fetcher.Offline)
@@ -26,11 +26,11 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.toHttp
import com.vitorpamplona.quartz.nip11RelayInfo.Nip11RelayInformation
import okhttp3.OkHttpClient
/** NIP-11 documents per relay, cached for an hour (errors too), with placeholders while loading. */
@Stable
class Nip11CachedRetriever(
val okHttpClient: (NormalizedRelayUrl) -> OkHttpClient,
private val retriever: Nip11Fetcher,
) {
private val relayInformationEmptyCache = LruCache<NormalizedRelayUrl, Nip11RelayInformation>(1000)
@@ -39,7 +39,6 @@ class Nip11CachedRetriever(
// the nullable argument compiled but never meant anything — get() returns null on a miss either
// way, which is what the readers below already branch on.
private val relayInformationDocumentCache = LruCache<NormalizedRelayUrl, RetrieveResult>(1000)
private val retriever = Nip11Retriever(okHttpClient)
/**
* Drops any cached NIP-11 document (including a cached *error*) for [relay], so the next
@@ -94,7 +93,7 @@ class Nip11CachedRetriever(
suspend fun loadRelayInfo(
relay: NormalizedRelayUrl,
onInfo: (Nip11RelayInformation) -> Unit,
onError: (NormalizedRelayUrl, Nip11Retriever.ErrorCode, String?) -> Unit,
onError: (NormalizedRelayUrl, Nip11ErrorCode, String?) -> Unit,
) {
val doc = relayInformationDocumentCache.get(relay)
if (doc != null) {
@@ -136,7 +135,7 @@ class Nip11CachedRetriever(
private suspend fun retrieve(
relay: NormalizedRelayUrl,
onInfo: (Nip11RelayInformation) -> Unit,
onError: (NormalizedRelayUrl, Nip11Retriever.ErrorCode, String?) -> Unit,
onError: (NormalizedRelayUrl, Nip11ErrorCode, String?) -> Unit,
) {
relayInformationDocumentCache.put(relay, RetrieveResult.Loading(getEmpty(relay)))
retriever.loadRelayInfo(
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2025 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.commons.relays.nip11RelayInfo
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.nip11RelayInfo.Nip11RelayInformation
/** Why a NIP-11 document could not be had. */
enum class Nip11ErrorCode {
FAIL_TO_ASSEMBLE_URL,
FAIL_TO_REACH_SERVER,
FAIL_TO_PARSE_RESULT,
FAIL_WITH_HTTP_STATUS,
}
/** Fetches a relay's NIP-11 document over whatever HTTP stack the platform has. */
interface Nip11Fetcher {
suspend fun loadRelayInfo(
relay: NormalizedRelayUrl,
onInfo: (Nip11RelayInformation) -> Unit,
onError: (NormalizedRelayUrl, Nip11ErrorCode, String?) -> Unit,
)
/** No network: every fetch fails as unreachable. For hosts that provide no fetcher. */
object Offline : Nip11Fetcher {
override suspend fun loadRelayInfo(
relay: NormalizedRelayUrl,
onInfo: (Nip11RelayInformation) -> Unit,
onError: (NormalizedRelayUrl, Nip11ErrorCode, String?) -> Unit,
) = onError(relay, Nip11ErrorCode.FAIL_TO_REACH_SERVER, null)
}
}
@@ -29,7 +29,7 @@ sealed class RetrieveResult(
) {
class Error(
data: Nip11RelayInformation,
val error: Nip11Retriever.ErrorCode,
val error: Nip11ErrorCode,
val msg: String? = null,
) : RetrieveResult(data, TimeUtils.now())
@@ -31,20 +31,14 @@ import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.coroutines.executeAsync
/** The OkHttp [Nip11Fetcher]. */
class Nip11Retriever(
val okHttpClient: (NormalizedRelayUrl) -> OkHttpClient,
) {
enum class ErrorCode {
FAIL_TO_ASSEMBLE_URL,
FAIL_TO_REACH_SERVER,
FAIL_TO_PARSE_RESULT,
FAIL_WITH_HTTP_STATUS,
}
suspend fun loadRelayInfo(
) : Nip11Fetcher {
override suspend fun loadRelayInfo(
relay: NormalizedRelayUrl,
onInfo: (Nip11RelayInformation) -> Unit,
onError: (NormalizedRelayUrl, ErrorCode, String?) -> Unit,
onError: (NormalizedRelayUrl, Nip11ErrorCode, String?) -> Unit,
) = withContext(Dispatchers.IO) {
val url = relay.toHttp()
val request =
@@ -57,7 +51,7 @@ class Nip11Retriever(
} catch (e: Exception) {
if (e is CancellationException) throw e
Log.e("RelayInfoFail", "Invalid URL ${relay.url}", e)
onError(relay, ErrorCode.FAIL_TO_ASSEMBLE_URL, e.message)
onError(relay, Nip11ErrorCode.FAIL_TO_ASSEMBLE_URL, e.message)
return@withContext
}
@@ -71,10 +65,10 @@ class Nip11Retriever(
if (body.startsWith("{")) {
onInfo(Nip11RelayInformation.fromJson(body))
} else {
onError(relay, ErrorCode.FAIL_TO_PARSE_RESULT, body)
onError(relay, Nip11ErrorCode.FAIL_TO_PARSE_RESULT, body)
}
} else {
onError(relay, ErrorCode.FAIL_WITH_HTTP_STATUS, response.code.toString())
onError(relay, Nip11ErrorCode.FAIL_WITH_HTTP_STATUS, response.code.toString())
}
} catch (e: Exception) {
if (e is CancellationException) throw e
@@ -83,13 +77,16 @@ class Nip11Retriever(
"Resulting Message from Relay ${relay.url} in not parseable: $body",
e,
)
onError(relay, ErrorCode.FAIL_TO_PARSE_RESULT, e.message)
onError(relay, Nip11ErrorCode.FAIL_TO_PARSE_RESULT, e.message)
}
}
} catch (e: Exception) {
if (e is CancellationException) throw e
Log.e("RelayInfoFail", "Failed to fetch NIP-11 from ${relay.url}", e)
onError(relay, ErrorCode.FAIL_TO_REACH_SERVER, e.message ?: e::class.simpleName)
onError(relay, Nip11ErrorCode.FAIL_TO_REACH_SERVER, e.message ?: e::class.simpleName)
}
}
}
/** A [Nip11CachedRetriever] over OkHttp, the client picked per relay. */
fun Nip11CachedRetriever(okHttpClient: (NormalizedRelayUrl) -> OkHttpClient): Nip11CachedRetriever = Nip11CachedRetriever(Nip11Retriever(okHttpClient))
@@ -40,13 +40,13 @@ class Nip11RetrieverTest {
}
val relay = NormalizedRelayUrl("ws://127.0.0.1:14591/")
var errorCode: Nip11Retriever.ErrorCode? = null
var errorCode: Nip11ErrorCode? = null
retriever.loadRelayInfo(
relay = relay,
onInfo = { fail("Expected an error, got relay info") },
onError = { _, code, _ -> errorCode = code },
)
assertEquals(Nip11Retriever.ErrorCode.FAIL_TO_REACH_SERVER, errorCode)
assertEquals(Nip11ErrorCode.FAIL_TO_REACH_SERVER, errorCode)
}
}

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Before

Width:  |  Height:  |  Size: 890 B

After

Width:  |  Height:  |  Size: 890 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

@@ -0,0 +1,4 @@
<vector android:height="128dp" android:viewportHeight="512"
android:viewportWidth="512" android:width="128dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#3A6CAC" android:fillType="evenOdd" android:pathData="M296.13,354.17c49.88,-5.89 102.94,-24.03 102.94,-110.19c0,-24.49 -8.62,-44.45 -22.67,-59.87c2.27,-5.89 9.52,-28.11 -2.73,-58.95c0,0 -18.14,-5.9 -60.76,22.67c-18.14,-4.98 -38.09,-8.16 -56.68,-8.16c-19.05,0 -39.01,3.18 -56.7,8.16c-43.08,-28.57 -61.22,-22.67 -61.22,-22.67c-12.24,30.83 -4.98,53.06 -2.72,58.95c-14.06,15.42 -22.68,35.38 -22.68,59.87c0,86.16 53.06,104.3 102.94,110.19c-6.34,5.45 -12.24,15.87 -14.51,30.39c-12.7,5.44 -45.81,15.87 -65.76,-18.59c0,0 -11.8,-21.31 -34.01,-22.67c0,0 -22.22,-0.45 -1.81,13.59c0,0 14.96,6.81 24.94,32.65c0,0 13.6,43.09 76.18,29.48v38.54c0,5.91 -4.53,12.7 -15.86,10.89C96.14,438.98 32.2,354.63 32.2,255.77c0,-123.81 100.22,-224.02 224.03,-224.02c123.35,0 224.02,100.22 223.57,224.02c0,98.86 -63.95,182.75 -152.83,212.69c-11.34,2.27 -15.87,-4.53 -15.87,-10.89V395.45C311.1,374.58 304.29,360.98 296.13,354.17L296.13,354.17zM512,256.23C512,114.73 397.26,0 256.23,0C114.73,0 0,114.73 0,256.23C0,397.26 114.73,512 256.23,512C397.26,512 512,397.26 512,256.23L512,256.23z"/>
</vector>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="200dp"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="200dp">
<path
android:fillColor="#FF000000"
android:pathData="M17.578,12.201c-0.76,-0.692 -1.721,-1.251 -2.704,-1.81 -0.446,-0.246 -1.81,-1.318 -1.34,-2.838l-0.851,-0.358c1.342,-2.078 3.085,-4.134 5.229,-6.056 -1.721,0.581 -3.24,1.476 -4.379,3.062 0.67,-1.407 1.765,-2.793 2.972,-4.201 -1.654,1.185 -3.084,2.525 -3.979,4.313l0.627,-2.503c-0.894,1.608 -1.52,3.24 -1.766,4.871l-1.317,-0.535 -0.223,0.178c1.162,2.078 0.559,3.174 -0.022,3.553 -1.162,0.783 -2.838,1.788 -3.688,2.659 -1.609,1.654 -2.078,3.218 -1.921,5.296 0.157,2.66 2.101,4.873 4.67,5.744 1.14,0.38 2.19,0.424 3.352,0.424 1.877,0 3.799,-0.491 5.207,-1.676a6.551,6.551 0,0 0,2.369 -5.027,6.875 6.875,0 0,0 -2.236,-5.096zM14.025,21.073c-0.09,0.402 -0.38,0.894 -0.737,1.341 0.134,-0.246 0.246,-0.492 0.313,-0.76 0.559,-1.989 0.805,-2.904 0.537,-5.095 -0.045,-0.224 -0.135,-0.938 -0.471,-1.721 -0.468,-1.185 -1.184,-2.303 -1.272,-2.548 -0.157,-0.38 -0.38,-1.989 -0.403,-3.084 0.023,0.938 0.089,2.659 0.335,3.329 0.067,0.225 0.715,1.229 1.185,2.459 0.312,0.849 0.38,1.632 0.446,1.854 0.224,1.007 -0.045,2.705 -0.401,4.313 -0.111,0.581 -0.426,1.252 -0.828,1.766 0.225,-0.313 0.402,-0.715 0.537,-1.185 0.269,-0.938 0.38,-2.145 0.356,-2.905 -0.021,-0.446 -0.222,-1.407 -0.558,-2.278 -0.201,-0.47 -0.492,-0.961 -0.692,-1.297 -0.224,-0.335 -0.224,-1.072 -0.313,-1.921 0.021,0.916 -0.068,1.385 0.156,2.033 0.134,0.379 0.625,0.916 0.759,1.43 0.201,0.693 0.402,1.453 0.381,1.922 0,0.536 -0.022,1.52 -0.269,2.593 -0.157,0.804 -0.515,1.497 -1.095,1.943 0.246,-0.312 0.38,-0.625 0.447,-0.938 0.089,-0.469 0.111,-0.916 0.156,-1.475a5.96,5.96 0,0 0,-0.111 -1.721c-0.179,-0.805 -0.469,-1.608 -0.604,-2.168 0.022,0.626 0.269,1.408 0.381,2.235 0.089,0.604 0.044,1.206 0.021,1.742 -0.021,0.627 -0.223,1.722 -0.492,2.258 -0.268,-0.112 -0.357,-0.269 -0.537,-0.491 -0.223,-0.291 -0.357,-0.604 -0.491,-0.962a5.043,5.043 0,0 1,-0.291 -0.915,3.071 3.071,0 0,1 0.559,-2.213c0.469,-0.671 0.559,-0.716 0.715,-1.497 -0.223,0.692 -0.379,0.759 -0.871,1.341 -0.559,0.647 -0.648,1.586 -0.648,2.346 0,0.313 0.134,0.671 0.246,1.007 0.134,0.356 0.268,0.714 0.447,0.982 0.134,0.223 0.313,0.379 0.469,0.491 -0.581,-0.156 -1.184,-0.379 -1.564,-0.692 -0.938,-0.805 -1.765,-2.167 -1.877,-3.375 -0.089,-0.982 0.804,-2.413 2.078,-3.128 1.073,-0.626 1.318,-1.319 1.542,-2.459 -0.313,0.983 -0.626,1.833 -1.654,2.348 -1.475,0.804 -2.235,2.1 -2.167,3.352 0.112,1.586 0.737,2.682 2.011,3.554 0.291,0.2 0.693,0.401 1.118,0.559 -1.587,-0.381 -1.788,-0.604 -2.324,-1.229 0,-0.045 -0.134,-0.135 -0.134,-0.156 -0.715,-0.805 -1.609,-2.19 -1.922,-3.464 -0.112,-0.447 -0.224,-0.916 -0.089,-1.363 0.581,-2.101 1.854,-2.905 3.128,-3.775 0.313,-0.225 0.626,-0.426 0.916,-0.649 0.715,-0.559 0.894,-2.012 1.05,-2.838 -0.29,1.006 -0.603,2.258 -1.162,2.659 -0.29,0.224 -0.648,0.402 -0.938,0.604 -1.318,0.894 -2.637,1.743 -3.24,3.91 -0.134,0.56 -0.044,0.962 0.089,1.498 0.335,1.317 1.229,2.748 1.989,3.597l0.134,0.135c0.335,0.381 0.76,0.67 1.274,0.871a5.945,5.945 0,0 1,-1.296 -0.469c-2.078,-1.005 -3.463,-3.173 -3.553,-4.939 -0.179,-3.597 1.542,-4.647 3.151,-5.966 0.894,-0.737 2.145,-1.095 2.86,-2.413 0.134,-0.291 0.224,-0.916 0.045,-1.587 -0.067,-0.224 -0.402,-1.028 -0.537,-1.207l1.989,0.872c-0.044,0.938 -0.067,1.698 0.112,2.391 0.2,0.76 1.184,1.854 1.586,3.129 0.783,2.41 0.583,5.561 0.023,8.019z" />
</vector>
@@ -0,0 +1,4 @@
<vector android:height="120dp" android:viewportHeight="47"
android:viewportWidth="47" android:width="120dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#712F8F" android:fillType="evenOdd" android:pathData="M35,11C37.209,11 39,9.209 39,7C39,4.791 37.209,3 35,3C32.791,3 31,4.791 31,7C31,9.209 32.791,11 35,11ZM35,14C38.866,14 42,10.866 42,7C42,3.134 38.866,0 35,0C31.134,0 28,3.134 28,7C28,8.359 28.387,9.627 29.057,10.7L26.611,13.146C25.019,11.828 22.976,11.035 20.747,11.035C18.586,11.035 16.598,11.781 15.029,13.029L11.259,9.259C11.73,8.448 12,7.505 12,6.5C12,3.462 9.538,1 6.5,1C3.462,1 1,3.462 1,6.5C1,9.538 3.462,12 6.5,12C7.442,12 8.328,11.763 9.103,11.346L13.012,15.255C12.088,16.689 11.552,18.397 11.552,20.23C11.552,22.265 12.213,24.145 13.332,25.669L11.709,27.291C10.509,26.476 9.06,26 7.5,26C3.358,26 0,29.358 0,33.5C0,37.642 3.358,41 7.5,41C11.642,41 15,37.642 15,33.5C15,32.003 14.561,30.608 13.805,29.437L15.477,27.766C16.969,28.812 18.786,29.426 20.747,29.426C22.612,29.426 24.347,28.871 25.796,27.917L30.589,32.711C29.588,34.132 29,35.865 29,37.736C29,42.56 32.911,46.471 37.736,46.471C42.56,46.471 46.471,42.56 46.471,37.736C46.471,32.911 42.56,29 37.736,29C35.865,29 34.132,29.588 32.71,30.589L28.002,25.881C29.218,24.322 29.942,22.361 29.942,20.23C29.942,18.465 29.445,16.817 28.583,15.417L31.152,12.848C32.256,13.576 33.578,14 35,14ZM9,6.5C9,7.881 7.881,9 6.5,9C5.119,9 4,7.881 4,6.5C4,5.119 5.119,4 6.5,4C7.881,4 9,5.119 9,6.5ZM7.5,38C9.985,38 12,35.985 12,33.5C12,31.015 9.985,29 7.5,29C5.015,29 3,31.015 3,33.5C3,35.985 5.015,38 7.5,38ZM43.471,37.736C43.471,40.903 40.903,43.471 37.736,43.471C34.568,43.471 32,40.903 32,37.736C32,34.568 34.568,32 37.736,32C40.903,32 43.471,34.568 43.471,37.736ZM26.942,20.23C26.942,23.652 24.169,26.426 20.747,26.426C17.326,26.426 14.552,23.652 14.552,20.23C14.552,16.809 17.326,14.035 20.747,14.035C24.169,14.035 26.942,16.809 26.942,20.23Z"/>
</vector>