fix: address the audit of the shared UI settings and display locals

- UiSettings (enums) and UiSettingsFlow move on to headless commons, and
  UiSettingsState to commons.state. Their StringResource labels become
  `resourceId` extension properties in commonsUI (the TorType pattern).
  commons applies the serialization plugin, so UiSettings gets its
  kotlinx serializer back: in commonsUI it had none, and the
  encrypted-preferences fallback (JsonMapper.fromJson<UiSettings>) would
  silently drop a user's old settings. New UiSettingsSerializationTest
  round-trips it.
- tools/r8-verify/reflection-contract.txt names the eight persisted
  settings enums by their new package; the release check would fail.
- LocalDisplaySettings is a compositionLocalOf: it follows Wi-Fi/metered
  changes, and as a static local it recomposed everything under the theme.
  It drops the three fields nothing read.
- The remaining avatar sites (drawer, account switcher, top bar, group
  cards, ...) read LocalDisplaySettings instead of a one-off snapshot of
  accountViewModel.settings, so they follow setting changes like the feed.
- 13 loaders left with an unused accountViewModel parameter after the
  LocalCache switch drop it (206 call sites).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0168wY9t7i9NC5u3svyMxEz6
This commit is contained in:
Claude
2026-09-24 15:51:48 +00:00
parent 1f1b6dab80
commit c3f60fd8af
168 changed files with 620 additions and 479 deletions
@@ -22282,7 +22282,7 @@ SPLcom/vitorpamplona/amethyst/AppModules;->getThumbnailDiskCache()Lcom/vitorpamp
SPLcom/vitorpamplona/amethyst/AppModules;->getTorManager()Lcom/vitorpamplona/amethyst/ui/tor/TorManager;
SPLcom/vitorpamplona/amethyst/AppModules;->getTorPrefs()Lcom/vitorpamplona/amethyst/model/preferences/TorSharedPreferences;
SPLcom/vitorpamplona/amethyst/AppModules;->getUiPrefs()Lcom/vitorpamplona/amethyst/model/preferences/UiSharedPreferences;
SPLcom/vitorpamplona/amethyst/AppModules;->getUiState()Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState;
SPLcom/vitorpamplona/amethyst/AppModules;->getUiState()Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState;
SPLcom/vitorpamplona/amethyst/AppModules;->getVideoCache()Lcom/vitorpamplona/amethyst/service/playback/diskCache/VideoCache;
SPLcom/vitorpamplona/amethyst/AppModules;->httpUsageInterceptor$lambda$0(Lcom/vitorpamplona/amethyst/AppModules;)Z
SPLcom/vitorpamplona/amethyst/AppModules;->httpUsageInterceptor$lambda$1(Lcom/vitorpamplona/amethyst/AppModules;)Z
@@ -22301,7 +22301,7 @@ SPLcom/vitorpamplona/amethyst/AppModules;->signerPermissionStore_delegate$lambda
SPLcom/vitorpamplona/amethyst/AppModules;->thumbnailDiskCache_delegate$lambda$0(Lcom/vitorpamplona/amethyst/AppModules;)Lcom/vitorpamplona/amethyst/service/images/ThumbnailDiskCache;
SPLcom/vitorpamplona/amethyst/AppModules;->torPrefs_delegate$lambda$0(Lcom/vitorpamplona/amethyst/AppModules;)Lcom/vitorpamplona/amethyst/model/preferences/TorSharedPreferences;
SPLcom/vitorpamplona/amethyst/AppModules;->uiPrefs_delegate$lambda$0(Lcom/vitorpamplona/amethyst/AppModules;)Lcom/vitorpamplona/amethyst/model/preferences/UiSharedPreferences;
SPLcom/vitorpamplona/amethyst/AppModules;->uiState_delegate$lambda$0(Lcom/vitorpamplona/amethyst/AppModules;)Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState;
SPLcom/vitorpamplona/amethyst/AppModules;->uiState_delegate$lambda$0(Lcom/vitorpamplona/amethyst/AppModules;)Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState;
SPLcom/vitorpamplona/amethyst/AppModules;->videoCache_delegate$lambda$0(Lcom/vitorpamplona/amethyst/AppModules;)Lcom/vitorpamplona/amethyst/service/playback/diskCache/VideoCache;
Lcom/vitorpamplona/amethyst/AppModules$$ExternalSyntheticLambda0;
SPLcom/vitorpamplona/amethyst/AppModules$$ExternalSyntheticLambda0;-><init>(Landroid/content/Context;)V
@@ -24832,49 +24832,49 @@ SPLcom/vitorpamplona/amethyst/ui/screen/ComposableSingletons$AccountScreenKt;->l
Lcom/vitorpamplona/amethyst/ui/screen/ComposableSingletons$AccountScreenKt$$ExternalSyntheticLambda0;
SPLcom/vitorpamplona/amethyst/ui/screen/ComposableSingletons$AccountScreenKt$$ExternalSyntheticLambda0;-><init>()V
SPLcom/vitorpamplona/amethyst/ui/screen/ComposableSingletons$AccountScreenKt$$ExternalSyntheticLambda0;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState;-><clinit>()V
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState;-><init>(Lcom/vitorpamplona/amethyst/commons/model/UiSettingsFlow;Lkotlinx/coroutines/flow/StateFlow;Lkotlinx/coroutines/CoroutineScope;)V
Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$WhenMappings;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$WhenMappings;-><clinit>()V
Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showImages$1;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showImages$1;-><init>(Lkotlin/coroutines/Continuation;)V
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showImages$1;->invoke(Lcom/vitorpamplona/amethyst/commons/model/ConnectivityType;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showImages$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showImages$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showImages$1$WhenMappings;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showImages$1$WhenMappings;-><clinit>()V
Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showProfilePictures$1;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showProfilePictures$1;-><init>(Lkotlin/coroutines/Continuation;)V
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showProfilePictures$1;->invoke(Lcom/vitorpamplona/amethyst/commons/model/ConnectivityType;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showProfilePictures$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showProfilePictures$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showProfilePictures$1$WhenMappings;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showProfilePictures$1$WhenMappings;-><clinit>()V
Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showUrlPreview$1;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showUrlPreview$1;-><init>(Lkotlin/coroutines/Continuation;)V
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showUrlPreview$1;->invoke(Lcom/vitorpamplona/amethyst/commons/model/ConnectivityType;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showUrlPreview$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showUrlPreview$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showUrlPreview$1$WhenMappings;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$showUrlPreview$1$WhenMappings;-><clinit>()V
Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$special$$inlined$map$1;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$special$$inlined$map$1;-><init>(Lkotlinx/coroutines/flow/Flow;)V
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$special$$inlined$map$1;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$special$$inlined$map$1$1;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$special$$inlined$map$1$1;-><init>(Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$special$$inlined$map$1;Lkotlin/coroutines/Continuation;)V
Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$special$$inlined$map$1$2;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$special$$inlined$map$1$2;-><init>(Lkotlinx/coroutines/flow/FlowCollector;)V
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$special$$inlined$map$1$2;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$special$$inlined$map$1$2$1;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$special$$inlined$map$1$2$1;-><init>(Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$special$$inlined$map$1$2;Lkotlin/coroutines/Continuation;)V
Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$startVideoPlayback$1;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$startVideoPlayback$1;-><init>(Lkotlin/coroutines/Continuation;)V
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$startVideoPlayback$1;->invoke(Lcom/vitorpamplona/amethyst/commons/model/ConnectivityType;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$startVideoPlayback$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$startVideoPlayback$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
Lcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$startVideoPlayback$1$WhenMappings;
SPLcom/vitorpamplona/amethyst/commons/ui/screen/UiSettingsState$startVideoPlayback$1$WhenMappings;-><clinit>()V
Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState;-><clinit>()V
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState;-><init>(Lcom/vitorpamplona/amethyst/commons/model/UiSettingsFlow;Lkotlinx/coroutines/flow/StateFlow;Lkotlinx/coroutines/CoroutineScope;)V
Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState$WhenMappings;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$WhenMappings;-><clinit>()V
Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showImages$1;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showImages$1;-><init>(Lkotlin/coroutines/Continuation;)V
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showImages$1;->invoke(Lcom/vitorpamplona/amethyst/commons/model/ConnectivityType;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showImages$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showImages$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showImages$1$WhenMappings;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showImages$1$WhenMappings;-><clinit>()V
Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showProfilePictures$1;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showProfilePictures$1;-><init>(Lkotlin/coroutines/Continuation;)V
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showProfilePictures$1;->invoke(Lcom/vitorpamplona/amethyst/commons/model/ConnectivityType;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showProfilePictures$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showProfilePictures$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showProfilePictures$1$WhenMappings;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showProfilePictures$1$WhenMappings;-><clinit>()V
Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showUrlPreview$1;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showUrlPreview$1;-><init>(Lkotlin/coroutines/Continuation;)V
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showUrlPreview$1;->invoke(Lcom/vitorpamplona/amethyst/commons/model/ConnectivityType;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showUrlPreview$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showUrlPreview$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showUrlPreview$1$WhenMappings;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$showUrlPreview$1$WhenMappings;-><clinit>()V
Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState$special$$inlined$map$1;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$special$$inlined$map$1;-><init>(Lkotlinx/coroutines/flow/Flow;)V
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$special$$inlined$map$1;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState$special$$inlined$map$1$1;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$special$$inlined$map$1$1;-><init>(Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState$special$$inlined$map$1;Lkotlin/coroutines/Continuation;)V
Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState$special$$inlined$map$1$2;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$special$$inlined$map$1$2;-><init>(Lkotlinx/coroutines/flow/FlowCollector;)V
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$special$$inlined$map$1$2;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState$special$$inlined$map$1$2$1;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$special$$inlined$map$1$2$1;-><init>(Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState$special$$inlined$map$1$2;Lkotlin/coroutines/Continuation;)V
Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState$startVideoPlayback$1;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$startVideoPlayback$1;-><init>(Lkotlin/coroutines/Continuation;)V
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$startVideoPlayback$1;->invoke(Lcom/vitorpamplona/amethyst/commons/model/ConnectivityType;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$startVideoPlayback$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$startVideoPlayback$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
Lcom/vitorpamplona/amethyst/commons/state/UiSettingsState$startVideoPlayback$1$WhenMappings;
SPLcom/vitorpamplona/amethyst/commons/state/UiSettingsState$startVideoPlayback$1$WhenMappings;-><clinit>()V
Lcom/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssembler;
SPLcom/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssembler;-><clinit>()V
SPLcom/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssembler;-><init>(Lcom/vitorpamplona/quartz/nip01Core/relay/client/INostrClient;)V
@@ -56,8 +56,8 @@ import com.vitorpamplona.amethyst.commons.service.http.OnionLocationCache
import com.vitorpamplona.amethyst.commons.service.lnurl.OkHttpLnurlEndpointResolver
import com.vitorpamplona.amethyst.commons.service.pow.PoWPolicy
import com.vitorpamplona.amethyst.commons.service.pow.PoWPublishQueue
import com.vitorpamplona.amethyst.commons.state.UiSettingsState
import com.vitorpamplona.amethyst.commons.tor.TorSettings
import com.vitorpamplona.amethyst.commons.ui.screen.UiSettingsState
import com.vitorpamplona.amethyst.connectedApps.DataStoreNostrSignerPermissionStore
import com.vitorpamplona.amethyst.connectedApps.nip46.DataStoreNip46ClientStore
import com.vitorpamplona.amethyst.model.Account
@@ -39,7 +39,6 @@ import com.vitorpamplona.amethyst.commons.resources.relay_auth_purpose_read_outb
import com.vitorpamplona.amethyst.commons.resources.relay_auth_purpose_read_venue
import com.vitorpamplona.amethyst.commons.resources.relay_auth_purpose_send_dm
import com.vitorpamplona.amethyst.commons.resources.relay_auth_purpose_thread
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import org.jetbrains.compose.resources.StringResource
@@ -51,7 +50,6 @@ import org.jetbrains.compose.resources.StringResource
@Composable
internal fun LoadRelayAuthUser(
pubkey: HexKey,
accountViewModel: AccountViewModel,
content: @Composable (User?) -> Unit,
) {
var user by remember(pubkey) { mutableStateOf(LocalCache.getUserIfExists(pubkey)) }
@@ -99,6 +99,7 @@ import com.vitorpamplona.amethyst.commons.resources.relay_auth_why_thread
import com.vitorpamplona.amethyst.commons.resources.relay_auth_why_thread_with
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.RelayIconFilter
import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo
@@ -404,8 +405,8 @@ private fun RelayHeader(
contentDescription = null,
colorFilter = RelayIconFilter,
modifier = Modifier.size(34.dp).clip(MaterialTheme.shapes.small),
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
)
Column {
Text(
@@ -466,7 +467,7 @@ private fun ReasonSentence(
InlineTextContent(
Placeholder(22.sp, 22.sp, PlaceholderVerticalAlign.TextCenter),
) {
LoadRelayAuthUser(face, accountViewModel) { user ->
LoadRelayAuthUser(face) { user ->
if (user != null) ClickableUserPicture(user, 20.dp, accountViewModel)
}
},
@@ -193,7 +193,7 @@ fun PeerAvatarCell(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
LoadUser(baseUserHex = peerPubKey, accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = peerPubKey) { user ->
if (user != null) {
ClickableUserPicture(
baseUser = user,
@@ -235,7 +235,7 @@ fun GroupCallPictures(
0 -> {}
1 -> {
LoadUser(baseUserHex = userList[0], accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = userList[0]) { user ->
if (user != null) {
ClickableUserPicture(
baseUser = user,
@@ -350,7 +350,7 @@ fun GroupCallNames(
0 -> {}
1 -> {
LoadUser(baseUserHex = userList[0], accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = userList[0]) { user ->
if (user != null) {
UsernameDisplay(
baseUser = user,
@@ -378,7 +378,7 @@ fun GroupCallNames(
color = textColor,
)
}
LoadUser(baseUserHex = userList[i], accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = userList[i]) { user ->
if (user != null) {
UsernameDisplay(
baseUser = user,
@@ -147,7 +147,7 @@ fun DisplayEvent(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadNote(hex, accountViewModel) {
LoadNote(hex) {
if (it != null) {
DisplayNoteLink(it, hex, additionalChars, accountViewModel, nav)
} else {
@@ -51,6 +51,7 @@ import com.vitorpamplona.amethyst.commons.resources.concord_invite_card_join
import com.vitorpamplona.amethyst.commons.resources.concord_invite_card_subtitle
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.quartz.concord.cord05Invites.CommunityInvite
@@ -139,8 +140,8 @@ fun ConcordInvitePreviewRow(
.size(52.dp)
.clip(CircleShape)
.border(1.5.dp, MaterialTheme.colorScheme.primary.copy(alpha = 0.35f), CircleShape),
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif = autoPlayGif,
)
Column(Modifier.weight(1f)) {
@@ -56,6 +56,7 @@ import com.vitorpamplona.amethyst.commons.resources.relay_group_open
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.LoadRelayGroupChannel
@@ -86,7 +87,7 @@ fun RelayGroupCard(
val groupId = remember(invite) { invite.toGroupId() }
LoadRelayGroupChannel(groupId, accountViewModel) { channel ->
LoadRelayGroupChannel(groupId) { channel ->
RelayGroupCardContent(channel, invite.code, accountViewModel, nav)
}
}
@@ -148,8 +149,8 @@ private fun RelayGroupCardContent(
.size(52.dp)
.clip(CircleShape)
.border(1.5.dp, MaterialTheme.colorScheme.primary.copy(alpha = 0.35f), CircleShape),
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif = autoPlayGif,
)
@@ -862,7 +862,7 @@ fun TagLink(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadUser(baseUserHex = word.hex, accountViewModel) {
LoadUser(baseUserHex = word.hex) {
if (it == null) {
Text(text = word.segmentText)
} else {
@@ -879,7 +879,6 @@ fun TagLink(
@Composable
fun LoadNote(
baseNoteHex: String,
accountViewModel: AccountViewModel,
content: @Composable (Note?) -> Unit,
) {
var note by
@@ -903,7 +902,7 @@ fun TagLink(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadNote(baseNoteHex = word.hex, accountViewModel) {
LoadNote(baseNoteHex = word.hex) {
if (it == null) {
Text(text = remember { word.segmentText.toShortDisplay() })
} else {
@@ -42,6 +42,7 @@ import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChann
import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.concord_home_title
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.ChannelFinderFilterAssemblerSubscription
@@ -279,8 +280,8 @@ fun GroupEntryAvatar(
model = display.model,
contentDescription = display.label,
modifier = Modifier.size(size).clip(CircleShape),
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif = false,
)
}
@@ -75,6 +75,7 @@ import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncIma
import com.vitorpamplona.amethyst.commons.ui.loadPluralStringRes
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.AccountPictureModifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp
@@ -238,8 +239,8 @@ private fun AccountPicture(
model = userInfo?.info?.profilePicture(),
contentDescription = stringRes(Res.string.profile_image),
modifier = AccountPictureModifier,
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif =
accountViewModel.settings.autoPlayVideosFlow
.collectAsStateWithLifecycle()
@@ -121,6 +121,7 @@ import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncIma
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness
import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer
@@ -315,8 +316,8 @@ fun ProfileContentTemplate(
.clip(shape = CircleShape)
.border(3.dp, MaterialTheme.colorScheme.onBackground, CircleShape)
.clickable(onClick = onClick),
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif =
accountViewModel.settings.autoPlayVideosFlow
.collectAsStateWithLifecycle()
@@ -42,6 +42,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar
import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon
import com.vitorpamplona.amethyst.commons.ui.note.SearchIcon
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.HeaderPictureModifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size22Modifier
@@ -142,8 +143,8 @@ internal fun LoggedInUserPictureDrawer(
contentDescription = stringRes(id = Res.string.your_profile_image),
modifier = HeaderPictureModifier,
contentScale = ContentScale.Crop,
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif =
accountViewModel.settings.autoPlayVideosFlow
.collectAsStateWithLifecycle()
@@ -92,7 +92,6 @@ fun LoadDecryptedContentOrNull(
@Composable
fun LoadAddressableNote(
address: Address,
accountViewModel: AccountViewModel,
content: @Composable (AddressableNote?) -> Unit,
) {
val note by produceState(
@@ -150,7 +149,6 @@ fun LoadOts(
@Composable
fun LoadPublicChatChannel(
id: String,
accountViewModel: AccountViewModel,
content: @Composable (PublicChatChannel) -> Unit,
) {
val channel by produceStateIfNotNull(LocalCache.getPublicChatChannelIfExists(id), id) {
@@ -163,7 +161,6 @@ fun LoadPublicChatChannel(
@Composable
fun LoadEphemeralChatChannel(
id: RoomId,
accountViewModel: AccountViewModel,
content: @Composable (EphemeralChatChannel) -> Unit,
) {
val channel =
@@ -177,7 +174,6 @@ fun LoadEphemeralChatChannel(
@Composable
fun LoadLiveActivityChannel(
id: Address,
accountViewModel: AccountViewModel,
content: @Composable (LiveActivitiesChannel) -> Unit,
) {
val channel =
@@ -87,6 +87,7 @@ import com.vitorpamplona.amethyst.commons.ui.note.RepostedIcon
import com.vitorpamplona.amethyst.commons.ui.note.ScoreTagSmall
import com.vitorpamplona.amethyst.commons.ui.note.ZappedIcon
import com.vitorpamplona.amethyst.commons.ui.richtext.InLineIconRenderer
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange
import com.vitorpamplona.amethyst.commons.ui.theme.HalfTopPadding
@@ -806,8 +807,8 @@ fun WatchUserMetadataAndFollowsAndRenderUserProfilePicture(
contentDescription = stringRes(id = Res.string.profile_image),
modifier = MaterialTheme.colorScheme.profile35dpModifier,
contentScale = ContentScale.Crop,
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif = autoPlayGif,
)
}
@@ -315,7 +315,7 @@ fun DisplayStatusInner(
}
nostrATag != null -> {
LoadAddressableNote(nostrATag, accountViewModel) { note ->
LoadAddressableNote(nostrATag) { note ->
if (note != null) {
Spacer(modifier = StdHorzSpacer)
IconButton(
@@ -339,7 +339,7 @@ fun DisplayStatusInner(
}
nostrETag != null -> {
LoadNote(baseNoteHex = nostrETag.eventId, accountViewModel) {
LoadNote(baseNoteHex = nostrETag.eventId) {
if (it != null) {
Spacer(modifier = StdHorzSpacer)
IconButton(
@@ -363,7 +363,7 @@ fun DisplayStatusInner(
}
nostrPTag != null -> {
LoadUser(baseUserHex = nostrPTag, accountViewModel) { user ->
LoadUser(baseUserHex = nostrPTag) { user ->
if (user != null) {
Spacer(modifier = StdHorzSpacer)
IconButton(
@@ -96,6 +96,7 @@ import com.vitorpamplona.amethyst.commons.ui.note.RenderCashuMint
import com.vitorpamplona.amethyst.commons.ui.note.RenderFedimint
import com.vitorpamplona.amethyst.commons.ui.note.RenderMintRecommendation
import com.vitorpamplona.amethyst.commons.ui.note.elements.StaleRelayHint
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.state.produceCachedStateAsync
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer
@@ -922,7 +923,7 @@ private fun RenderApprovalIfNeeded(
baseNote.event?.communityAddress()
}
communityAddress?.let {
LoadAddressableNote(it, accountViewModel) { community ->
LoadAddressableNote(it) { community ->
if (community != null) {
val showApproveButton by observeCommunityApprovalNeedStatus(baseNote, community, accountViewModel)
if (showApproveButton == true) {
@@ -2427,7 +2428,7 @@ fun RenderAuthorImages(
if (noteEvent is ChannelMessageEvent) {
val baseChannelHex = noteEvent.channelId()
if (baseChannelHex != null) {
LoadPublicChatChannel(baseChannelHex, accountViewModel) { channel ->
LoadPublicChatChannel(baseChannelHex) { channel ->
ChannelNotePicture(
channel,
accountViewModel,
@@ -2449,8 +2450,8 @@ private fun ChannelNotePicture(
model = model,
contentDescription = stringRes(Res.string.group_picture),
modifier = MaterialTheme.colorScheme.channelNotePictureModifier,
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif =
accountViewModel.settings.autoPlayVideosFlow
.collectAsStateWithLifecycle()
@@ -428,7 +428,7 @@ fun PayReaction(
val authorPubkey = baseNote.author?.pubkeyHex ?: return
val address = remember(authorPubkey) { PaymentTargetsEvent.createAddress(authorPubkey) }
LoadAddressableNote(address, accountViewModel) { note ->
LoadAddressableNote(address) { note ->
var expanded by remember { mutableStateOf(false) }
ClickableBox(
@@ -58,6 +58,7 @@ import com.vitorpamplona.amethyst.commons.ui.components.ClickableBox
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.LargeRelayIconModifier
import com.vitorpamplona.amethyst.commons.ui.theme.RelayIconFilter
@@ -161,9 +162,9 @@ fun RenderRelay(
RenderRelayIcon(
displayUrl = relayInfo.id ?: relay.url,
iconUrl = relayInfo.icon,
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
pingInMs = 0,
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadRobohash = LocalDisplaySettings.current.loadRobohash,
iconModifier = iconModifier,
)
}
@@ -359,7 +359,6 @@ private fun EmojiSelector(
) {
LoadAddressableNote(
accountViewModel.account.emoji.getEmojiPackSelectionAddress(),
accountViewModel,
) { emptyNote ->
emptyNote?.let { usersEmojiList ->
val collections by observeNoteEventAndMapNotNull(usersEmojiList, accountViewModel) { event: EmojiPackSelectionEvent ->
@@ -387,7 +386,7 @@ fun EmojiCollectionGallery(
state = listState,
) {
itemsIndexed(emojiCollections, key = { _, item -> item }) { _, item ->
LoadAddressableNote(item, accountViewModel) {
LoadAddressableNote(item) {
it?.let { WatchAndRenderNote(it, bgColor, accountViewModel, nav, onClick) }
}
}
@@ -49,6 +49,7 @@ import com.vitorpamplona.amethyst.commons.ui.components.UserAvatar
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.note.FollowingIcon
import com.vitorpamplona.amethyst.commons.ui.note.ScoreTag
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserContactCardsScore
@@ -105,7 +106,7 @@ fun DisplayBlankAuthor(
robot = "authornotfound",
contentDescription = stringRes(Res.string.unknown_author),
modifier = nullModifier,
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadRobohash = LocalDisplaySettings.current.loadRobohash,
)
}
@@ -117,7 +118,7 @@ fun UserPicture(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadUser(baseUserHex = userHex, accountViewModel) {
LoadUser(baseUserHex = userHex) {
if (it != null) {
UserPicture(
user = it,
@@ -241,7 +242,7 @@ fun NonClickableUserPictures(
0 -> {}
1 -> {
LoadUser(baseUserHex = userHexList.first(), accountViewModel) {
LoadUser(baseUserHex = userHexList.first()) {
it?.let { BaseUserPicture(it, size, accountViewModel, outerModifier = Modifier) }
}
}
@@ -249,7 +250,7 @@ fun NonClickableUserPictures(
2 -> {
val userList = userHexList
LoadUser(baseUserHex = userList[0], accountViewModel) {
LoadUser(baseUserHex = userList[0]) {
it?.let {
BaseUserPicture(
it,
@@ -259,7 +260,7 @@ fun NonClickableUserPictures(
)
}
}
LoadUser(baseUserHex = userList[1], accountViewModel) {
LoadUser(baseUserHex = userList[1]) {
it?.let {
BaseUserPicture(
it,
@@ -274,7 +275,7 @@ fun NonClickableUserPictures(
3 -> {
val userList = userHexList
LoadUser(baseUserHex = userList[0], accountViewModel) {
LoadUser(baseUserHex = userList[0]) {
it?.let {
BaseUserPicture(
it,
@@ -284,7 +285,7 @@ fun NonClickableUserPictures(
)
}
}
LoadUser(baseUserHex = userList[1], accountViewModel) {
LoadUser(baseUserHex = userList[1]) {
it?.let {
BaseUserPicture(
it,
@@ -294,7 +295,7 @@ fun NonClickableUserPictures(
)
}
}
LoadUser(baseUserHex = userList[2], accountViewModel) {
LoadUser(baseUserHex = userList[2]) {
it?.let {
BaseUserPicture(
it,
@@ -309,7 +310,7 @@ fun NonClickableUserPictures(
else -> {
val userList = userHexList
LoadUser(baseUserHex = userList[0], accountViewModel) {
LoadUser(baseUserHex = userList[0]) {
it?.let {
BaseUserPicture(
it,
@@ -319,7 +320,7 @@ fun NonClickableUserPictures(
)
}
}
LoadUser(baseUserHex = userList[1], accountViewModel) {
LoadUser(baseUserHex = userList[1]) {
it?.let {
BaseUserPicture(
it,
@@ -329,7 +330,7 @@ fun NonClickableUserPictures(
)
}
}
LoadUser(baseUserHex = userList[2], accountViewModel) {
LoadUser(baseUserHex = userList[2]) {
it?.let {
BaseUserPicture(
it,
@@ -339,7 +340,7 @@ fun NonClickableUserPictures(
)
}
}
LoadUser(baseUserHex = userList[3], accountViewModel) {
LoadUser(baseUserHex = userList[3]) {
it?.let {
BaseUserPicture(
it,
@@ -392,7 +393,7 @@ fun BaseUserPicture(
outerModifier: Modifier = Modifier.size(size),
) {
Box(outerModifier, contentAlignment = Alignment.TopEnd) {
LoadUser(baseUserHex, accountViewModel) {
LoadUser(baseUserHex) {
if (it != null) {
ObserveAndDrawInnerUserPicture(it, size, accountViewModel, innerModifier)
@@ -34,7 +34,6 @@ import kotlinx.collections.immutable.toImmutableList
fun WatchAndLoadMyEmojiList(accountViewModel: AccountViewModel) {
LoadAddressableNote(
EmojiPackSelectionEvent.createAddress(accountViewModel.userProfile().pubkeyHex),
accountViewModel,
) { emptyNote ->
emptyNote?.let { usersEmojiList ->
val collections by observeNoteEventAndMapNotNull(usersEmojiList, accountViewModel) { event: EmojiPackSelectionEvent ->
@@ -42,7 +41,7 @@ fun WatchAndLoadMyEmojiList(accountViewModel: AccountViewModel) {
}
collections?.forEach { address ->
LoadAddressableNote(address, accountViewModel) { note ->
LoadAddressableNote(address) { note ->
if (note != null) {
EventFinderFilterAssemblerSubscription(note, accountViewModel)
}
@@ -244,7 +244,7 @@ private fun OfferRecipientRow(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadUser(baseUserHex = pubKey, accountViewModel) { user ->
LoadUser(baseUserHex = pubKey) { user ->
if (user != null) {
Row(
verticalAlignment = Alignment.CenterVertically,
@@ -106,7 +106,6 @@ fun ObserveRelayListForDMs(
) {
LoadAddressableNote(
ChatMessageRelayListEvent.createAddress(pubkey),
accountViewModel,
) { relayList ->
if (relayList != null) {
val relayListEvent by observeNoteEvent<ChatMessageRelayListEvent>(relayList, accountViewModel)
@@ -49,13 +49,13 @@ fun ShowForkInformation(
val forkedAddress = remember(noteEvent) { noteEvent.forkFromAddress() }
val forkedEvent = remember(noteEvent) { noteEvent.forkFromVersion() }
if (forkedAddress != null) {
LoadAddressableNote(forkedAddress, accountViewModel) { addressableNote ->
LoadAddressableNote(forkedAddress) { addressableNote ->
if (addressableNote != null) {
ForkMark(addressableNote, modifier, accountViewModel, nav)
}
}
} else if (forkedEvent != null) {
LoadNote(forkedEvent, accountViewModel) { event ->
LoadNote(forkedEvent) { event ->
if (event != null) {
ForkMark(event, modifier, accountViewModel, nav)
}
@@ -123,7 +123,7 @@ fun ShareNoteAsImageScreen(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadNote(id, accountViewModel) { note ->
LoadNote(id) { note ->
if (note != null) {
ShareNoteAsImageScreen(note, accountViewModel, nav)
}
@@ -142,7 +142,7 @@ fun ShareNoteAsImageFileScreen(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadNote(id, accountViewModel) { note ->
LoadNote(id) { note ->
if (note != null) {
ShareNoteAsImageFileScreen(note, accountViewModel, nav)
}
@@ -94,7 +94,7 @@ fun ShareNoteAsQrScreen(
Scaffold(
topBar = { TopBarWithBackButton(stringRes(Res.string.share_as_qr), nav) },
) { pad ->
LoadNote(id, accountViewModel) { note ->
LoadNote(id) { note ->
if (note != null) {
ShareNoteAsQrScreenContent(note, accountViewModel, nav, pad)
}
@@ -585,7 +585,7 @@ private fun RelatedEventRow(
val address = remember(aTag) { Address(aTag.kind, aTag.pubKeyHex, aTag.dTag) }
val shape = RoundedCornerShape(8.dp)
LoadAddressableNote(address, accountViewModel) { note ->
LoadAddressableNote(address) { note ->
if (note == null) return@LoadAddressableNote
val noteState by observeNote(note, accountViewModel)
@@ -709,7 +709,7 @@ fun ByAuthorChip(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadUser(baseUserHex = authorHex, accountViewModel = accountViewModel) { author ->
LoadUser(baseUserHex = authorHex) { author ->
if (author == null) return@LoadUser
Surface(
@@ -85,7 +85,7 @@ fun RenderAppRecommendation(
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
recommendations.forEach { recommendation ->
LoadAddressableNote(recommendation.address, accountViewModel) { appNote ->
LoadAddressableNote(recommendation.address) { appNote ->
appNote?.let {
if (it.event == null) {
EventFinderFilterAssemblerSubscription(it, accountViewModel)
@@ -221,7 +221,7 @@ fun RenderAttestation(
if (quotesLeft > 0) {
if (aboutAddress != null) {
LoadAddressableNote(aboutAddress, accountViewModel) {
LoadAddressableNote(aboutAddress) {
if (it != null) {
Spacer(modifier = DoubleVertSpacer)
NoteCompose(
@@ -238,7 +238,7 @@ fun RenderAttestation(
}
}
} else if (aboutEvent != null) {
LoadNote(aboutEvent, accountViewModel) {
LoadNote(aboutEvent) {
if (it != null) {
Spacer(modifier = DoubleVertSpacer)
NoteCompose(
@@ -345,7 +345,7 @@ fun RenderAttestationRequest(
if (quotesLeft > 0) {
when {
aboutAddress != null -> {
LoadAddressableNote(aboutAddress, accountViewModel) {
LoadAddressableNote(aboutAddress) {
if (it != null) {
Spacer(modifier = DoubleVertSpacer)
Text(
@@ -369,7 +369,7 @@ fun RenderAttestationRequest(
}
aboutEvent != null -> {
LoadNote(aboutEvent, accountViewModel) {
LoadNote(aboutEvent) {
if (it != null) {
Spacer(modifier = DoubleVertSpacer)
Text(
@@ -393,7 +393,7 @@ fun RenderAttestationRequest(
}
aboutPubkey != null -> {
LoadUser(aboutPubkey, accountViewModel) {
LoadUser(aboutPubkey) {
if (it != null) {
Spacer(modifier = DoubleVertSpacer)
Text(
@@ -458,7 +458,7 @@ fun RenderAttestorRecommendation(
)
}
LoadUser(aboutPubKey, accountViewModel) {
LoadUser(aboutPubKey) {
if (it != null) {
Spacer(modifier = DoubleVertSpacer)
UserCompose(it, accountViewModel = accountViewModel, nav = nav)
@@ -73,7 +73,7 @@ private fun LoadAppointmentBehind(
) {
val address = remember(event) { event.calendarEventAddress() } ?: return
LoadAddressableNote(address, accountViewModel) { appointment ->
LoadAddressableNote(address) { appointment ->
if (appointment != null) {
EventFinderFilterAssemblerSubscription(appointment, accountViewModel)
}
@@ -91,7 +91,7 @@ fun RenderChessGame(
ChessGameViewer(
pgnContent = event.pgn(),
playerContent = { playerHex ->
LoadUser(playerHex, accountViewModel) { user ->
LoadUser(playerHex) { user ->
if (user != null) {
UserChip(user = user, accountViewModel = accountViewModel, nav = nav)
} else {
@@ -196,7 +196,7 @@ fun RenderLiveChessChallenge(
fontWeight = FontWeight.Bold,
)
event.opponentPubkey()?.let { opponentHex ->
LoadUser(opponentHex, accountViewModel) { user ->
LoadUser(opponentHex) { user ->
if (user != null) {
UserChip(user = user, accountViewModel = accountViewModel, nav = nav)
}
@@ -313,7 +313,7 @@ fun RenderLiveChessGameEnd(
)
event.opponentPubkey()?.let { opponentHex ->
LoadUser(opponentHex, accountViewModel) { user ->
LoadUser(opponentHex) { user ->
if (user != null) {
UserChip(user = user, accountViewModel = accountViewModel, nav = nav)
}
@@ -340,7 +340,7 @@ fun RenderLiveChessGameEnd(
ChessGameViewer(
pgnContent = pgn,
playerContent = { playerHex ->
LoadUser(playerHex, accountViewModel) { user ->
LoadUser(playerHex) { user ->
if (user != null) {
UserChip(user = user, accountViewModel = accountViewModel, nav = nav)
} else {
@@ -79,6 +79,7 @@ import com.vitorpamplona.amethyst.commons.resources.quick_action_share
import com.vitorpamplona.amethyst.commons.resources.quick_action_share_browser_link
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder
import com.vitorpamplona.amethyst.commons.ui.theme.ButtonPadding
@@ -338,8 +339,8 @@ fun ShortCommunityHeader(
contentDescription = stringRes(Res.string.profile_image),
contentScale = ContentScale.Crop,
modifier = HeaderPictureModifier,
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif =
accountViewModel.settings.autoPlayVideosFlow
.collectAsStateWithLifecycle()
@@ -393,8 +394,8 @@ fun ShortCommunityHeaderNoActions(
contentDescription = stringRes(Res.string.profile_image),
contentScale = ContentScale.Crop,
modifier = HeaderPictureModifier,
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif =
accountViewModel.settings.autoPlayVideosFlow
.collectAsStateWithLifecycle()
@@ -182,7 +182,6 @@ private fun EmojiListOptions(
) {
LoadAddressableNote(
accountViewModel.account.emoji.getEmojiPackSelectionAddress(),
accountViewModel,
) {
it?.let { usersEmojiList ->
val hasAddedThis by observeNoteAndMap(usersEmojiList, accountViewModel) {
@@ -127,7 +127,7 @@ fun RenderEntityRating(
Column(Modifier.fillMaxWidth()) {
if (targetAddress != null) {
LoadAddressableNote(targetAddress, accountViewModel) { targetNote ->
LoadAddressableNote(targetAddress) { targetNote ->
targetNote?.let {
RatedPublicationCard(
targetNote = it,
@@ -142,7 +142,7 @@ fun RenderEntityRating(
// The spec's default mark is `event`, and such a rating names its target by event id
// rather than by coordinate. Without this the card printed the raw 64-hex id as its
// title, which tells a reader nothing about what was rated.
LoadNote(targetEventId, accountViewModel) { targetNote ->
LoadNote(targetEventId) { targetNote ->
if (targetNote != null) {
RatedNoteCard(targetNote, mark, accountViewModel, nav)
} else {
@@ -50,7 +50,7 @@ fun FileStorageHeaderDisplay(
val eventHeader = (baseNote.event as? FileStorageHeaderEvent) ?: return
val dataEventId = eventHeader.dataEventId() ?: return
LoadNote(baseNoteHex = dataEventId, accountViewModel) { contentNote ->
LoadNote(baseNoteHex = dataEventId) { contentNote ->
if (contentNote != null) {
ObserverAndRenderNIP95(baseNote, contentNote, roundedCorner, contentScale, accountViewModel)
}
@@ -169,7 +169,7 @@ fun RenderGeocacheFoundLog(
// Loaded even for an unverified log: the cache's name is what tells a reader in a feed what
// was actually found, and "Found it!" on its own says nothing.
LoadAddressableNote(address, accountViewModel) { cacheNote ->
LoadAddressableNote(address) { cacheNote ->
if (cacheNote == null) {
GeocacheFoundLogCard(noteEvent, showImages, if (hasProof) FoundLogProof.UNKNOWN else FoundLogProof.NONE)
} else {
@@ -451,7 +451,7 @@ private fun RenderGitPatchEvent(
val repository = remember(noteEvent) { noteEvent.repositoryAddress() }
if (repository != null) {
Spacer(modifier = StdVertSpacer)
LoadAddressableNote(repository, accountViewModel) {
LoadAddressableNote(repository) {
if (it != null) {
RenderShortRepositoryHeader(it, accountViewModel, nav)
}
@@ -550,7 +550,7 @@ private fun RenderGitIssueEvent(
val repository = remember(noteEvent) { noteEvent.repositoryAddress() }
if (repository != null) {
Spacer(modifier = StdVertSpacer)
LoadAddressableNote(repository, accountViewModel) {
LoadAddressableNote(repository) {
if (it != null) {
RenderShortRepositoryHeader(it, accountViewModel, nav)
}
@@ -610,7 +610,7 @@ private fun RenderGitPullRequestEvent(
GitCardContainer {
val repository = remember(noteEvent) { noteEvent.repositoryAddress() }
if (repository != null) {
LoadAddressableNote(repository, accountViewModel) {
LoadAddressableNote(repository) {
if (it != null) {
RenderShortRepositoryHeader(it, accountViewModel, nav)
}
@@ -751,7 +751,7 @@ private fun RenderGitPullRequestUpdateEvent(
val repository = remember(noteEvent) { noteEvent.repositoryAddress() }
if (repository != null) {
Spacer(modifier = StdVertSpacer)
LoadAddressableNote(repository, accountViewModel) {
LoadAddressableNote(repository) {
if (it != null) {
RenderShortRepositoryHeader(it, accountViewModel, nav)
}
@@ -79,7 +79,7 @@ fun RenderInteractiveStory(
val currentScene = readingState?.currentScene()
if (currentScene != null && currentScene != rootEvent.address()) {
LoadAddressableNote(currentScene, accountViewModel) { currentSceneBaseNote ->
LoadAddressableNote(currentScene) { currentSceneBaseNote ->
currentSceneBaseNote?.let {
val currentSceneEvent by observeNoteEvent<InteractiveStoryBaseEvent>(it, accountViewModel)
@@ -168,7 +168,7 @@ fun RenderInteractiveStory(
if (options.isNotEmpty()) {
Column(Modifier.padding(top = 10.dp)) {
options.forEach { opt ->
LoadAddressableNote(opt.address, accountViewModel) { note ->
LoadAddressableNote(opt.address) { note ->
if (note != null) {
EventFinderFilterAssemblerSubscription(note, accountViewModel)
@@ -61,7 +61,7 @@ fun RenderLiveActivityChatMessage(
}
showChannelInfo?.let {
LoadLiveActivityChannel(it, accountViewModel) {
LoadLiveActivityChannel(it) {
LiveActivitiesChannelHeader(
baseChannel = it,
showVideo = false,
@@ -340,7 +340,6 @@ private fun ParentMeetingSpaceLink(
com.vitorpamplona.amethyst.ui.note.LoadAddressableNote(
address = spaceAddress,
accountViewModel = accountViewModel,
) { spaceNote ->
spaceNote ?: return@LoadAddressableNote
val spaceEvent = spaceNote.event as? MeetingSpaceEvent
@@ -260,7 +260,7 @@ fun MusicPlaylistHeader(
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.06f),
)
}
LoadAddressableNote(address, accountViewModel) { trackNote ->
LoadAddressableNote(address) { trackNote ->
if (trackNote != null) {
PlaylistTrackRow(
position = index + 1,
@@ -678,7 +678,7 @@ private fun RenderMusicPlaylistPreview() {
}
ThemeComparisonColumn {
LoadNote(baseNoteHex = event.address().toValue(), accountViewModel = mockAccountViewModel()) { note ->
LoadNote(baseNoteHex = event.address().toValue()) { note ->
note?.let {
RenderMusicPlaylist(
note = it,
@@ -710,7 +710,7 @@ private fun RenderMusicPlaylistCollaborativePrivatePreview() {
remember(event) { runBlocking { withContext(Dispatchers.IO) { LocalCache.justConsume(event, null, true) } } }
ThemeComparisonColumn {
LoadNote(baseNoteHex = event.address().toValue(), accountViewModel = mockAccountViewModel()) { note ->
LoadNote(baseNoteHex = event.address().toValue()) { note ->
note?.let {
RenderMusicPlaylist(
note = it,
@@ -740,7 +740,7 @@ private fun MusicPlaylistCoverPreview() {
remember(event) { runBlocking { withContext(Dispatchers.IO) { LocalCache.justConsume(event, null, true) } } }
ThemeComparisonColumn {
LoadNote(baseNoteHex = event.address().toValue(), accountViewModel = mockAccountViewModel()) { note ->
LoadNote(baseNoteHex = event.address().toValue()) { note ->
note?.let {
MusicPlaylistCover(
image = null,
@@ -517,7 +517,7 @@ private fun RenderMusicTrackPreview() {
remember(event) { runBlocking { withContext(Dispatchers.IO) { LocalCache.justConsume(event, null, true) } } }
ThemeComparisonColumn {
LoadNote(baseNoteHex = event.address().toValue(), accountViewModel = mockAccountViewModel()) { note ->
LoadNote(baseNoteHex = event.address().toValue()) { note ->
note?.let {
RenderMusicTrack(
note = it,
@@ -549,7 +549,7 @@ private fun RenderMusicTrackExplicitPreview() {
remember(event) { runBlocking { withContext(Dispatchers.IO) { LocalCache.justConsume(event, null, true) } } }
ThemeComparisonColumn {
LoadNote(baseNoteHex = event.address().toValue(), accountViewModel = mockAccountViewModel()) { note ->
LoadNote(baseNoteHex = event.address().toValue()) { note ->
note?.let {
RenderMusicTrack(
note = it,
@@ -571,7 +571,7 @@ private fun MusicTrackCoverPreview() {
remember(event) { runBlocking { withContext(Dispatchers.IO) { LocalCache.justConsume(event, null, true) } } }
ThemeComparisonColumn {
LoadNote(baseNoteHex = event.address().toValue(), accountViewModel = mockAccountViewModel()) { note ->
LoadNote(baseNoteHex = event.address().toValue()) { note ->
note?.let { MusicTrackCover(image = null, note = it, accountViewModel = mockAccountViewModel()) }
}
}
@@ -47,6 +47,7 @@ import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.podcast_hosts_and_guests
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp
import com.vitorpamplona.amethyst.commons.ui.theme.grayText
@@ -104,7 +105,7 @@ private fun PersonItem(
val pubKey = remember(person) { person.nostrPubKey() }
if (pubKey != null) {
LoadUser(pubKey, accountViewModel) { user ->
LoadUser(pubKey) { user ->
if (user != null) {
NostrPersonCard(user, person.role, accountViewModel, nav)
} else {
@@ -157,8 +158,8 @@ private fun FreeTextPersonCard(
model = person.img,
contentDescription = person.name,
modifier = Modifier.size(56.dp).clip(CircleShape),
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
)
},
name = {
@@ -319,7 +319,7 @@ internal fun PublicationSectionRow(
val address = ref.address
if (address != null) {
LoadAddressableNote(address, accountViewModel) { sectionNote ->
LoadAddressableNote(address) { sectionNote ->
if (sectionNote != null) {
ObservedSectionRow(position, ref, sectionNote, accountViewModel, nav)
} else {
@@ -327,7 +327,7 @@ internal fun PublicationSectionRow(
}
}
} else if (ref.eventId != null) {
LoadNote(ref.eventId!!, accountViewModel) { sectionNote ->
LoadNote(ref.eventId!!) { sectionNote ->
if (sectionNote != null) {
ObservedSectionRow(position, ref, sectionNote, accountViewModel, nav)
} else {
@@ -113,7 +113,7 @@ fun RenderPublicationSection(
// A chapter arrived at from a search, a mention or a wikilink has nothing around it to say
// what it is a chapter *of*. The index names itself, so show it above the title.
noteEvent.publicationAddress()?.let { address ->
LoadAddressableNote(address, accountViewModel) { indexNote ->
LoadAddressableNote(address) { indexNote ->
indexNote?.let { PublicationCrumb(it, accountViewModel, nav) }
}
}
@@ -142,7 +142,7 @@ fun RenderPublicationSection(
}
noteEvent.publicationAddress()?.let { address ->
LoadAddressableNote(address, accountViewModel) { indexNote ->
LoadAddressableNote(address) { indexNote ->
indexNote?.let { PublicationPager(noteEvent, it, accountViewModel, nav) }
}
}
@@ -253,11 +253,11 @@ private fun PagerEnd(
// The index's own title shows immediately; the neighbour is still observed, because observing
// is what fetches it and it carries the better title.
if (address != null) {
LoadAddressableNote(address, accountViewModel) { target ->
LoadAddressableNote(address) { target ->
target?.let { PagerButton(ref, it, isBack, accountViewModel, nav, modifier) }
}
} else if (eventId != null) {
LoadNote(eventId, accountViewModel) { target ->
LoadNote(eventId) { target ->
target?.let { PagerButton(ref, it, isBack, accountViewModel, nav, modifier) }
}
}
@@ -51,6 +51,7 @@ import com.vitorpamplona.amethyst.commons.nip29RelayGroups.ui.RelayNameChip
import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName
@@ -135,8 +136,8 @@ fun RelayGroupChannelHeader(
model = channel.profilePicture(),
contentDescription = channel.toBestDisplayName(),
modifier = Modifier.size(28.dp).clip(CircleShape),
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
)
if (dmOther != null) {
@@ -58,7 +58,7 @@ fun RenderPostApproval(
Column(Modifier.fillMaxWidth()) {
noteEvent.communityAddresses().forEach { tag ->
LoadAddressableNote(tag, accountViewModel) { baseNote ->
LoadAddressableNote(tag) { baseNote ->
baseNote?.let {
RenderCommunity(
baseNote = it,
@@ -82,7 +82,7 @@ fun RenderVideoCollaboration(
// quotesLeft guards the recursion: the embedded video can itself credit other work, and
// NoteCompose is what decrements it on the way down.
if (video != null && quotesLeft > 0) {
LoadAddressableNote(video, accountViewModel) { videoNote ->
LoadAddressableNote(video) { videoNote ->
videoNote?.let {
NoteCompose(
baseNote = it,
@@ -103,7 +103,7 @@ private fun RenderVideoCredit(
) {
when (val target = credit.target) {
is CreditTarget.Person ->
LoadUser(target.pubKey, accountViewModel) { user ->
LoadUser(target.pubKey) { user ->
// Until the profile arrives there is no name to print, and a hex key in the
// credits reads as noise rather than as a person.
user?.let {
@@ -169,12 +169,12 @@ private fun VideoListMemberPoster(
) {
when (item) {
is AddressBookmark ->
LoadAddressableNote(item.address, accountViewModel) { note ->
LoadAddressableNote(item.address) { note ->
note?.let { VideoPoster(it, accountViewModel) { nav.nav(Route.Note(addressTag(item.address))) } }
}
is EventBookmark ->
LoadNote(item.eventId, accountViewModel) { note ->
LoadNote(item.eventId) { note ->
note?.let { VideoPoster(it, accountViewModel) { nav.nav(Route.Note(item.eventId)) } }
}
}
@@ -76,7 +76,7 @@ fun WithSnoPalette(
is NEvent -> LoadPaletteNote(entity.hex, accountViewModel, content)
is NNote -> LoadPaletteNote(entity.hex, accountViewModel, content)
is NAddress ->
LoadAddressableNote(entity.address(), accountViewModel) { note ->
LoadAddressableNote(entity.address()) { note ->
content(remember(note?.event) { note?.event?.let { SnoPaletteEventReader.read(it) } })
}
// A reference the parser accepted as well-formed but that names nothing
@@ -91,7 +91,7 @@ private fun LoadPaletteNote(
accountViewModel: AccountViewModel,
content: @Composable (SnoPalette?) -> Unit,
) {
LoadNote(hex, accountViewModel) { note ->
LoadNote(hex) { note ->
// The kind is deliberately not checked: §1.3b says this format "does
// not define a palette kind and does not want one", and a reader that
// accepts the shape reads whatever convention wins. An event that is
@@ -587,7 +587,7 @@ private fun BundledAssetsList(
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
assetIds.forEach { id ->
key(id) {
LoadAssetNote(id, accountViewModel) { assetNote ->
LoadAssetNote(id) { assetNote ->
if (assetNote != null) {
SoftwareAssetRow(assetNote, accountViewModel)
}
@@ -600,7 +600,6 @@ private fun BundledAssetsList(
@Composable
private fun LoadAssetNote(
eventId: String,
accountViewModel: AccountViewModel,
content: @Composable (Note?) -> Unit,
) {
val note by produceState<Note?>(initialValue = LocalCache.getNoteIfExists(eventId), eventId) {
@@ -95,7 +95,7 @@ fun RenderTextModificationEvent(
}
noteEvent.editedNote()?.let {
LoadNote(baseNoteHex = it.eventId, accountViewModel = accountViewModel) { baseOriginalNote ->
LoadNote(baseNoteHex = it.eventId) { baseOriginalNote ->
baseOriginalNote?.let {
}
}
@@ -133,7 +133,7 @@ fun RenderTextModificationEvent(
}
noteEvent.editedNote()?.let {
LoadNote(baseNoteHex = it.eventId, accountViewModel = accountViewModel) { baseNote ->
LoadNote(baseNoteHex = it.eventId) { baseNote ->
baseNote?.let {
val noteState by observeNote(baseNote, accountViewModel)
@@ -212,7 +212,7 @@ fun TorrentHeader(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadNote(baseNoteHex = torrentHex, accountViewModel = accountViewModel) {
LoadNote(baseNoteHex = torrentHex) {
if (it != null) {
ShortTorrentHeader(it, modifier, accountViewModel, nav)
}
@@ -213,7 +213,7 @@ private fun WikiArticleRow(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadAddressableNote(address, accountViewModel) { articleNote ->
LoadAddressableNote(address) { articleNote ->
if (articleNote != null) {
val article by observeNoteEvent<WikiNoteEvent>(articleNote, accountViewModel)
@@ -238,7 +238,7 @@ private fun WikiVersionRow(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadNote(eventId, accountViewModel) { versionNote ->
LoadNote(eventId) { versionNote ->
if (versionNote != null) {
val article by observeNoteEvent<WikiNoteEvent>(versionNote, accountViewModel)
@@ -58,7 +58,7 @@ fun UserMemberRow(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadUser(pubKey, accountViewModel) { user ->
LoadUser(pubKey) { user ->
user?.let {
Column(modifier = Modifier.fillMaxWidth()) {
UserCompose(it, accountViewModel = accountViewModel, nav = nav)
@@ -88,7 +88,7 @@ fun BookmarkMemberRow(
is AddressBookmark -> AddressMemberRow(item.address, quotesLeft, backgroundColor, accountViewModel, nav)
is EventBookmark ->
LoadNote(item.eventId, accountViewModel) { note ->
LoadNote(item.eventId) { note ->
note?.let {
NoteCompose(
baseNote = it,
@@ -114,7 +114,7 @@ fun AddressMemberRow(
) {
if (quotesLeft <= 0) return
LoadAddressableNote(address, accountViewModel) { note ->
LoadAddressableNote(address) { note ->
note?.let {
NoteCompose(
baseNote = it,
@@ -95,7 +95,7 @@ private fun MutedThreadRow(
) {
if (quotesLeft <= 0) return
LoadNote(eventId, accountViewModel) { note ->
LoadNote(eventId) { note ->
note?.let {
NoteCompose(
baseNote = it,
@@ -100,12 +100,12 @@ import com.vitorpamplona.amethyst.commons.service.broadcast.BroadcastTracker
import com.vitorpamplona.amethyst.commons.service.http.EmptyRoleBasedHttpClientBuilder
import com.vitorpamplona.amethyst.commons.service.http.IRoleBasedHttpClientBuilder
import com.vitorpamplona.amethyst.commons.service.pow.PoWCategory
import com.vitorpamplona.amethyst.commons.state.UiSettingsState
import com.vitorpamplona.amethyst.commons.tor.TorType
import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewState
import com.vitorpamplona.amethyst.commons.ui.components.toasts.ToastManager
import com.vitorpamplona.amethyst.commons.ui.loadStringRes
import com.vitorpamplona.amethyst.commons.ui.notifications.CardFeedState
import com.vitorpamplona.amethyst.commons.ui.screen.UiSettingsState
import com.vitorpamplona.amethyst.commons.ui.state.GenericBaseCache
import com.vitorpamplona.amethyst.commons.ui.state.GenericBaseCacheAsync
import com.vitorpamplona.amethyst.logTime
@@ -72,6 +72,7 @@ import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
import com.vitorpamplona.amethyst.commons.util.toShortDisplay
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel
@@ -269,7 +270,7 @@ private fun PersonCell(
Badge.ADDED -> "+" to tones.added
Badge.CHANGED -> "~" to tones.changed
}
LoadUser(pubKey, accountViewModel) { user ->
LoadUser(pubKey) { user ->
Column(
modifier.clip(RoundedCornerShape(12.dp)).clickable { nav.nav(Route.Profile(pubKey)) }.padding(vertical = 4.dp),
horizontalAlignment = Alignment.CenterHorizontally,
@@ -437,7 +438,7 @@ private fun LazyListScope.muteListItems(
if (threads.isNotEmpty()) {
item(key = "mute-threads-caption", contentType = "caption") { SectionCaption(stringRes(R.string.backup_entry_thread), Pad.padding(top = 18.dp)) }
items(threads, key = { "mute-thread-$it" }, contentType = { "note" }) { id ->
LoadNote(id, accountViewModel) { note ->
LoadNote(id) { note ->
if (note != null) {
NoteCompose(note, modifier = Modifier.padding(horizontal = 16.dp, vertical = 6.dp), makeItShort = true, quotesLeft = 1, accountViewModel = accountViewModel, nav = nav)
} else {
@@ -489,8 +490,8 @@ private fun FacePile(
model = observedPicture(pubKey, accountViewModel),
contentDescription = null,
modifier = Modifier.size(42.dp).clip(CircleShape),
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
)
}
}
@@ -688,8 +689,8 @@ private fun MiniProfileCard(
model = meta.picture,
contentDescription = null,
modifier = Modifier.size(46.dp).clip(CircleShape),
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
)
}
Column(Modifier.offset(y = (-20).dp), verticalArrangement = Arrangement.spacedBy(3.dp)) {
@@ -1122,7 +1123,7 @@ private fun GroupTileCard(
GroupTileContent(tile, tile.group.name ?: tile.group.groupId, null, accountViewModel, modifier, null)
return
}
LoadRelayGroupChannel(GroupId(tile.group.groupId, relay), accountViewModel) { channel ->
LoadRelayGroupChannel(GroupId(tile.group.groupId, relay)) { channel ->
// Subscribes to the group's relay-signed metadata (even when not joined) and recomposes
// when its name or picture arrives.
val state by observeChannel(channel, accountViewModel)
@@ -1158,8 +1159,8 @@ private fun GroupTileContent(
model = picture,
contentDescription = null,
modifier = Modifier.size(44.dp).clip(RoundedCornerShape(14.dp)),
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
)
Column {
Text(name, style = MaterialTheme.typography.titleSmall, maxLines = 1, overflow = TextOverflow.Ellipsis)
@@ -65,6 +65,7 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
import com.vitorpamplona.amethyst.commons.util.toShortDisplay
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel
@@ -425,8 +426,8 @@ private fun SpaceTile(
model = picture,
contentDescription = null,
modifier = Modifier.size(48.dp).clip(CircleShape),
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
)
Column {
Text(name, style = MaterialTheme.typography.titleSmall, maxLines = 1, overflow = TextOverflow.Ellipsis)
@@ -452,7 +453,7 @@ private fun LazyListScope.publicChatItems(
) {
val saved = (conflict.saved as? ChannelListEvent)?.tags?.channels().orEmpty()
spaceGrid("chat-", fates(saved, diff.channels) { it.eventId }, { it.eventId }) { tag, fate, modifier ->
LoadPublicChatChannel(tag.eventId, accountViewModel) { channel ->
LoadPublicChatChannel(tag.eventId) { channel ->
// Subscribes to the channel's metadata on relays and recomposes when it arrives.
val state by observeChannel(channel, accountViewModel)
val current = state?.channel ?: channel
@@ -508,7 +509,7 @@ private fun AddressableSpaceTile(
modifier: Modifier,
onClick: () -> Unit,
) {
LoadAddressableNote(address, accountViewModel) { note ->
LoadAddressableNote(address) { note ->
val event =
if (note != null) {
val state by observeNote(note, accountViewModel)
@@ -789,7 +790,7 @@ private fun ProviderCell(
Text("—", modifier, color = MaterialTheme.colorScheme.placeholderText)
return
}
LoadUser(pubKey, accountViewModel) { user ->
LoadUser(pubKey) { user ->
Row(
modifier.clip(RoundedCornerShape(8.dp)).clickable { nav.nav(Route.Profile(pubKey)) },
verticalAlignment = Alignment.CenterVertically,
@@ -801,8 +802,8 @@ private fun ProviderCell(
model = observedPicture(pubKey, accountViewModel),
contentDescription = null,
modifier = Modifier.size(22.dp).clip(CircleShape),
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
)
ProvideTextStyle(MaterialTheme.typography.labelMedium.copy(color = if (struck) color else MaterialTheme.colorScheme.onSurface, textDecoration = if (struck) TextDecoration.LineThrough else null)) {
if (user != null) {
@@ -422,7 +422,7 @@ internal fun ReviewEntry(
when (item) {
is ReviewItem.Person -> PersonEntry(item, accountViewModel, nav)
is ReviewItem.Thread ->
LoadNote(item.eventId, accountViewModel) { note ->
LoadNote(item.eventId) { note ->
if (note != null) {
Column(EntryPadding) {
NoteCompose(note, makeItShort = true, quotesLeft = 1, accountViewModel = accountViewModel, nav = nav)
@@ -433,7 +433,7 @@ internal fun ReviewEntry(
}
}
is ReviewItem.Addressable ->
LoadAddressableNote(item.address, accountViewModel) { note ->
LoadAddressableNote(item.address) { note ->
if (note != null) {
Column(EntryPadding) {
NoteCompose(note, makeItShort = true, quotesLeft = 1, accountViewModel = accountViewModel, nav = nav)
@@ -457,7 +457,7 @@ private fun PersonEntry(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadUser(item.pubKey, accountViewModel) { user ->
LoadUser(item.pubKey) { user ->
if (user == null) {
TextEntry(item.pubKey.toShortDisplay(), item.detail)
} else {
@@ -482,7 +482,7 @@ private fun PublicChatEntry(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadPublicChatChannel(item.channelId, accountViewModel) { channel ->
LoadPublicChatChannel(item.channelId) { channel ->
// Subscribes to the channel's metadata on relays and recomposes when it arrives.
val state by observeChannel(channel, accountViewModel)
val name = state?.channel?.toBestDisplayName() ?: channel.toBestDisplayName()
@@ -208,7 +208,7 @@ private fun AwardRow(
return
}
LoadAddressableNote(defAddr, accountViewModel) { defNote ->
LoadAddressableNote(defAddr) { defNote ->
if (defNote == null) {
StaticAwardRow(
definition = null,
@@ -59,7 +59,7 @@ fun ArticleBookmarkListManagementScreen(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadAddressableNote(address = articleAddress, accountViewModel = accountViewModel) {
LoadAddressableNote(address = articleAddress) {
it?.let {
ListManagementView(
modifier = Modifier.fillMaxSize().recalculateWindowInsets(),
@@ -58,7 +58,7 @@ fun PostBookmarkListManagementScreen(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadNote(baseNoteHex = postId, accountViewModel = accountViewModel) {
LoadNote(baseNoteHex = postId) {
it?.let {
ListManagementView(
modifier = Modifier.fillMaxSize().recalculateWindowInsets(),
@@ -450,7 +450,7 @@ private fun Person(
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(5.dp)) {
Text(prefix, style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
UserPicture(userHex = hex, size = Size20dp, accountViewModel = accountViewModel, nav = nav)
LoadUser(baseUserHex = hex, accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = hex) { user ->
if (user != null) UsernameDisplay(baseUser = user, fontWeight = FontWeight.Medium, accountViewModel = accountViewModel)
}
}
@@ -387,7 +387,7 @@ private fun Person(
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(5.dp)) {
Text(prefix, style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
UserPicture(userHex = hex, size = Size20dp, accountViewModel = accountViewModel, nav = nav)
LoadUser(baseUserHex = hex, accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = hex) { user ->
if (user != null) {
UsernameDisplay(baseUser = user, fontWeight = FontWeight.Medium, accountViewModel = accountViewModel)
}
@@ -741,7 +741,7 @@ private fun Person(
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(5.dp)) {
Text(prefix, style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
UserPicture(userHex = hex, size = Size20dp, accountViewModel = accountViewModel, nav = nav)
LoadUser(baseUserHex = hex, accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = hex) { user ->
if (user != null) {
UsernameDisplay(baseUser = user, fontWeight = FontWeight.Medium, accountViewModel = accountViewModel)
}
@@ -373,7 +373,7 @@ private fun ParticipantsRow(
size = Size30dp,
accountViewModel = accountViewModel,
)
LoadUser(baseUserHex = pubKey, accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = pubKey) { user ->
if (user != null) {
UsernameDisplay(
baseUser = user,
@@ -774,7 +774,7 @@ private fun UserRow(
nav: INav,
trailing: (@Composable () -> Unit)?,
) {
LoadUser(baseUserHex = pubKey, accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = pubKey) { user ->
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
@@ -292,7 +292,7 @@ private fun RecipientDeliveryRow(
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.fillMaxWidth(),
) {
LoadUser(baseUserHex = recipient.recipient, accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = recipient.recipient) { user ->
if (user != null) {
UserPicture(user, Size20dp, Modifier, accountViewModel, nav)
Row(modifier = Modifier.weight(1f)) {
@@ -72,7 +72,7 @@ fun RenderChatClip(
Row(verticalAlignment = Alignment.CenterVertically) {
UserPicture(authorHex, Size20dp, Modifier, accountViewModel, nav)
Spacer(StdHorzSpacer)
LoadUser(baseUserHex = authorHex, accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = authorHex) { user ->
if (user != null) {
UsernameDisplay(
baseUser = user,
@@ -84,7 +84,7 @@ fun RenderChatRaid(
Row(verticalAlignment = Alignment.CenterVertically) {
UserPicture(from.pubKeyHex, Size20dp, Modifier, accountViewModel, nav)
Spacer(StdHorzSpacer)
LoadUser(baseUserHex = from.pubKeyHex, accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = from.pubKeyHex) { user ->
if (user != null) {
UsernameDisplay(
baseUser = user,
@@ -104,7 +104,7 @@ fun RenderChatRaid(
UserPicture(to.pubKeyHex, Size20dp, Modifier, accountViewModel, nav)
Spacer(StdHorzSpacer)
LoadUser(baseUserHex = to.pubKeyHex, accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = to.pubKeyHex) { user ->
if (user != null) {
UsernameDisplay(
baseUser = user,
@@ -69,6 +69,7 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel
import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.service.location.LocationState
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserPicture
import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold
@@ -115,7 +116,7 @@ fun GeohashChatScreen(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadGeohashChannel(geohash, accountViewModel) { channel ->
LoadGeohashChannel(geohash) { channel ->
GeohashChatRoom(channel, teleported, accountViewModel, nav)
}
}
@@ -317,8 +318,8 @@ private fun GeohashIdentityAvatar(
model = picture,
contentDescription = "Posting as yourself — tap to go anonymous, long-press for a nickname",
modifier = avatarModifier,
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif = false,
)
} else {
@@ -24,7 +24,6 @@ import androidx.compose.runtime.Composable
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.model.geohashChat.GeohashChatChannel
import com.vitorpamplona.amethyst.ui.note.produceStateIfNotNull
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
/**
* Resolves the [GeohashChatChannel] for [geohash] from LocalCache, creating an
@@ -35,7 +34,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable
fun LoadGeohashChannel(
geohash: String,
accountViewModel: AccountViewModel,
content: @Composable (GeohashChatChannel) -> Unit,
) {
val channel =
@@ -45,6 +45,7 @@ import com.vitorpamplona.amethyst.commons.resources.marmot_change_photo
import com.vitorpamplona.amethyst.commons.resources.marmot_group_icon
import com.vitorpamplona.amethyst.commons.resources.marmot_remove_photo
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -99,8 +100,8 @@ fun MarmotGroupIconEditor(
.size(96.dp)
.clip(CircleShape)
.let { if (enabled) it.clickable { launcher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)) } else it },
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
)
Row(
@@ -132,6 +132,7 @@ import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe
import com.vitorpamplona.amethyst.commons.ui.loadStringRes
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.MediumRelayIconModifier
import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightChat
@@ -760,7 +761,7 @@ fun MemberRow(
nav = nav,
)
Column(modifier = Modifier.weight(1f)) {
LoadUser(baseUserHex = member.pubkey, accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = member.pubkey) { user ->
val displayName = user?.toBestDisplayName() ?: stringRes(Res.string.marmot_user_fallback_name, member.pubkey.take(16))
val youSuffix = stringRes(Res.string.marmot_member_suffix_you)
val adminSuffix = stringRes(Res.string.marmot_member_suffix_admin)
@@ -875,7 +876,7 @@ private fun ConfirmRemoveMemberDialog(
onDismissRequest = onDismiss,
title = { Text(stringRes(Res.string.marmot_remove_member)) },
text = {
LoadUser(baseUserHex = memberPubkey, accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = memberPubkey) { user ->
val name = user?.toBestDisplayName() ?: stringRes(Res.string.marmot_user_fallback_name, memberPubkey.take(16))
Text(stringRes(Res.string.marmot_remove_member_confirm, name))
}
@@ -904,7 +905,7 @@ private fun ConfirmGrantAdminDialog(
onDismissRequest = onDismiss,
title = { Text(stringRes(Res.string.marmot_grant_admin_title)) },
text = {
LoadUser(baseUserHex = memberPubkey, accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = memberPubkey) { user ->
val name = user?.toBestDisplayName() ?: stringRes(Res.string.marmot_user_fallback_name, memberPubkey.take(16))
Text(stringRes(Res.string.marmot_grant_admin_confirm, name))
}
@@ -933,7 +934,7 @@ private fun ConfirmRevokeAdminDialog(
onDismissRequest = onDismiss,
title = { Text(stringRes(Res.string.marmot_revoke_admin_title)) },
text = {
LoadUser(baseUserHex = memberPubkey, accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = memberPubkey) { user ->
val name = user?.toBestDisplayName() ?: stringRes(Res.string.marmot_user_fallback_name, memberPubkey.take(16))
Text(stringRes(Res.string.marmot_revoke_admin_confirm, name))
}
@@ -1025,9 +1026,9 @@ fun GroupRelayTile(
RenderRelayIcon(
displayUrl = relayInfo.id ?: fallbackUrl,
iconUrl = relayInfo.icon,
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
pingInMs = 0,
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadRobohash = LocalDisplaySettings.current.loadRobohash,
iconModifier = MediumRelayIconModifier,
)
@@ -131,7 +131,6 @@ fun ChatroomView(
for (userHex in room.users) {
LoadAddressableNote(
ChatMessageRelayListEvent.createAddress(userHex),
accountViewModel,
) { note ->
if (note != null) {
EventFinderFilterAssemblerSubscription(note, accountViewModel)
@@ -49,7 +49,7 @@ fun ChatroomHeader(
onClick: () -> Unit,
) {
if (room.users.size == 1) {
LoadUser(baseUserHex = room.users.first(), accountViewModel) { baseUser ->
LoadUser(baseUserHex = room.users.first()) { baseUser ->
if (baseUser != null) {
UserChatroomHeader(
baseUser = baseUser,
@@ -96,7 +96,7 @@ fun DmReportWarningCard(
) {
val counterpartHex = room.users.singleOrNull() ?: return
LoadUser(baseUserHex = counterpartHex, accountViewModel = accountViewModel) { user ->
LoadUser(baseUserHex = counterpartHex) { user ->
if (user != null) {
val flow = remember(user) { accountViewModel.createUserReportWarningFlow(user) }
val state by flow.collectAsStateWithLifecycle()
@@ -81,7 +81,7 @@ fun RenderRoomTopBar(
if (room.users.size == 1) {
TopBarExtensibleWithBackButton(
title = {
LoadUser(baseUserHex = room.users.first(), accountViewModel) { baseUser ->
LoadUser(baseUserHex = room.users.first()) { baseUser ->
if (baseUser != null) {
ClickableUserPicture(
baseUser = baseUser,
@@ -124,7 +124,7 @@ fun RenderRoomTopBar(
}
},
extendableRow = {
LoadUser(baseUserHex = room.users.first(), accountViewModel) {
LoadUser(baseUserHex = room.users.first()) {
if (it != null) {
UserCompose(
baseUser = it,
@@ -216,7 +216,7 @@ fun GroupMembersHeader(
state = rememberLazyListState(),
) {
itemsIndexed(list, key = { _, item -> item }) { _, item ->
LoadUser(baseUserHex = item, accountViewModel) {
LoadUser(baseUserHex = item) {
if (it != null) {
UserCompose(
baseUser = it,
@@ -81,14 +81,14 @@ fun DisplayUserSetAsSubject(
if (userList.size == 1) {
// Regular Design
Row {
LoadUser(baseUserHex = userList[0], accountViewModel) {
LoadUser(baseUserHex = userList[0]) {
it?.let { UsernameDisplay(it, Modifier.weight(1f), fontWeight = fontWeight, accountViewModel = accountViewModel) }
}
}
} else {
Row {
userList.take(4).forEachIndexed { index, value ->
LoadUser(baseUserHex = value, accountViewModel) {
LoadUser(baseUserHex = value) {
it?.let { ShortUsernameDisplay(baseUser = it, fontWeight = fontWeight, accountViewModel = accountViewModel) }
}
@@ -72,6 +72,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarP
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName
@@ -313,8 +314,8 @@ private fun CommunityHeader(
model = iconModel,
contentDescription = name,
modifier = Modifier.size(40.dp).clip(CircleShape).clickable(onClick = onOpen),
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif = autoPlayGif,
)
// The identity block — icon *and* name/subtitle — opens the community; the rest of the row and
@@ -78,6 +78,7 @@ import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncIma
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
import com.vitorpamplona.amethyst.commons.ui.loadStringRes
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.MediumRelayIconModifier
import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo
@@ -193,8 +194,8 @@ private fun ConcordIconHero(
model = iconModel,
contentDescription = displayName.ifBlank { stringRes(Res.string.concord_create_title) },
modifier = Modifier.size(104.dp).clip(CircleShape),
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif = autoPlayGif,
)
if (uploading) CircularProgressIndicator(modifier = Modifier.size(36.dp))
@@ -345,8 +346,8 @@ private fun ConcordRelayRow(
RenderRelayIcon(
displayUrl = relayInfo.id ?: relay.displayUrl(),
iconUrl = relayInfo.icon,
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
pingInMs = 0,
iconModifier = MediumRelayIconModifier,
)
@@ -53,7 +53,7 @@ fun EphemeralChatChannelView(
) {
if (channelId == null) return
LoadEphemeralChatChannel(channelId, accountViewModel) { ephem ->
LoadEphemeralChatChannel(channelId) { ephem ->
PrepareChannelViewModels(
baseChannel = ephem,
draft = draft,
@@ -51,7 +51,7 @@ fun EphemeralChatScreen(
DisappearingScaffold(
isInvertedLayout = true,
topBar = {
LoadEphemeralChatChannel(channelId, accountViewModel) {
LoadEphemeralChatChannel(channelId) {
EphemeralChatTopBar(it, accountViewModel, nav)
}
},
@@ -24,13 +24,11 @@ import androidx.compose.runtime.Composable
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel
import com.vitorpamplona.amethyst.ui.note.produceStateIfNotNull
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId
@Composable
fun LoadEphemeralChatChannel(
id: RoomId,
accountViewModel: AccountViewModel,
content: @Composable (EphemeralChatChannel) -> Unit,
) {
val channel =
@@ -42,6 +42,7 @@ import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.profile_image
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.HeaderPictureModifier
import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp
@@ -103,8 +104,8 @@ private fun DrawRelayIcon(
contentDescription = stringRes(Res.string.profile_image),
contentScale = ContentScale.Crop,
modifier = HeaderPictureModifier,
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif =
accountViewModel.settings.autoPlayVideosFlow
.collectAsStateWithLifecycle()
@@ -53,7 +53,7 @@ fun PublicChatChannelView(
) {
if (channelId == null) return
LoadPublicChatChannel(channelId, accountViewModel) {
LoadPublicChatChannel(channelId) {
PrepareChannelViewModels(
baseChannel = it,
draft = draft,
@@ -57,7 +57,7 @@ fun PublicChatChannelHeader(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadPublicChatChannel(channelHex, accountViewModel) {
LoadPublicChatChannel(channelHex) {
PublicChatChannelHeader(
it,
sendToChannel,
@@ -52,7 +52,7 @@ fun PublicChatChannelScreen(
DisappearingScaffold(
isInvertedLayout = true,
topBar = {
LoadPublicChatChannel(channelId, accountViewModel) {
LoadPublicChatChannel(channelId) {
PublicChatTopBar(it, accountViewModel, nav)
}
},
@@ -53,6 +53,7 @@ import com.vitorpamplona.amethyst.commons.resources.owner
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer
import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp
@@ -94,8 +95,8 @@ fun LongPublicChatChannelHeader(
model = it,
contentDescription = stringRes(Res.string.channel_image),
modifier = MaterialTheme.colorScheme.largeProfilePictureModifier,
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif =
accountViewModel.settings.autoPlayVideosFlow
.collectAsStateWithLifecycle()
@@ -144,7 +145,7 @@ fun LongPublicChatChannelHeader(
}
}
LoadNote(baseNoteHex = channel.idHex, accountViewModel) { loadingNote ->
LoadNote(baseNoteHex = channel.idHex) { loadingNote ->
loadingNote?.let { note ->
Row(
lineModifier,
@@ -43,6 +43,7 @@ import com.vitorpamplona.amethyst.commons.resources.Res
import com.vitorpamplona.amethyst.commons.resources.profile_image
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.HeaderPictureModifier
import com.vitorpamplona.amethyst.commons.ui.theme.RowColSpacing
@@ -72,8 +73,8 @@ fun ShortPublicChatChannelHeader(
contentDescription = stringRes(Res.string.profile_image),
contentScale = ContentScale.Crop,
modifier = HeaderPictureModifier,
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif =
accountViewModel.settings.autoPlayVideosFlow
.collectAsStateWithLifecycle()
@@ -115,7 +116,7 @@ fun ShortChannelActionOptions(
accountViewModel: AccountViewModel,
nav: INav,
) {
LoadNote(baseNoteHex = channel.idHex, accountViewModel) {
LoadNote(baseNoteHex = channel.idHex) {
it?.let {
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = RowColSpacing) {
LikeReaction(
@@ -94,7 +94,7 @@ fun ChannelMetadataScreen(
if (channelId == null) {
ChannelMetadataScreen(null as PublicChatChannel?, accountViewModel, nav)
} else {
LoadPublicChatChannel(channelId, accountViewModel) {
LoadPublicChatChannel(channelId) {
ChannelMetadataScreen(it, accountViewModel, nav)
}
}
@@ -56,7 +56,7 @@ fun LiveActivityChannelView(
) {
if (channelId == null) return
LoadLiveActivityChannel(channelId, accountViewModel) {
LoadLiveActivityChannel(channelId) {
PrepareChannelViewModels(
baseChannel = it,
draft = draft,
@@ -52,7 +52,7 @@ fun LiveActivityChannelScreen(
DisappearingScaffold(
isInvertedLayout = true,
topBar = {
LoadLiveActivityChannel(channelId, accountViewModel) {
LoadLiveActivityChannel(channelId) {
LaunchedEffect(it.info) {
it.info?.streaming()?.let {
OnlineChecker.resetIfOfflineToRetry(it)
@@ -63,7 +63,7 @@ fun LiveStreamGoalHeader(
) {
val goalId = channel.info?.goalEventId() ?: return
LoadNote(baseNoteHex = goalId, accountViewModel = accountViewModel) { goalNote ->
LoadNote(baseNoteHex = goalId) { goalNote ->
if (goalNote != null) {
GoalHeaderContent(goalNote, accountViewModel, nav)
}
@@ -91,7 +91,7 @@ fun LongLiveActivityChannelHeader(
RenderSummary(activity, callbackUri, accountViewModel, nav)
}
LoadAddressableNote(channel.address, accountViewModel) { loadingNote ->
LoadAddressableNote(channel.address) { loadingNote ->
loadingNote?.let { note ->
Row(
lineModifier,
@@ -24,13 +24,11 @@ import androidx.compose.runtime.Composable
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel
import com.vitorpamplona.amethyst.ui.note.produceStateIfNotNull
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.quartz.nip29RelayGroups.GroupId
@Composable
fun LoadRelayGroupChannel(
id: GroupId,
accountViewModel: AccountViewModel,
content: @Composable (RelayGroupChannel) -> Unit,
) {
val channel =
@@ -99,6 +99,7 @@ import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncIma
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings
import com.vitorpamplona.amethyst.commons.ui.stringRes
import com.vitorpamplona.amethyst.commons.ui.theme.warningColor
import com.vitorpamplona.amethyst.commons.util.sortedBySnapshot
@@ -973,8 +974,8 @@ private fun RelayGroupChannelRow(
model = channel.profilePicture(),
contentDescription = channel.toBestDisplayName(),
modifier = Modifier.size(40.dp).clip(CircleShape),
loadProfilePicture = accountViewModel.settings.showProfilePictures(),
loadRobohash = accountViewModel.settings.isNotPerformanceMode(),
loadProfilePicture = LocalDisplaySettings.current.showProfilePictures,
loadRobohash = LocalDisplaySettings.current.loadRobohash,
autoPlayGif = autoPlayGif,
)

Some files were not shown because too many files have changed in this diff Show More