refactor(sonar): merge chained if-else into when

Sonar — convert 'if (A) {…} else if (B) {…} else {…}' chains into
'when { A -> …; B -> …; else -> … }' across 33 files (~44 sites).
The change is mechanically equivalent: same conditions, same branch
order, same short-circuit evaluation, no public-signature impact.

The 70-branch event-type dispatch in ThreadFeedView.kt:594 is intentionally
left as if-else for now — the conversion would balloon to a 280-line diff
with no behavioural change, making review impractical.
This commit is contained in:
davotoula
2026-05-13 10:40:38 +02:00
parent 5e179326d4
commit 8ed7e63427
33 changed files with 1399 additions and 1104 deletions
@@ -2859,14 +2859,11 @@ class Account(
if (event == null) return null if (event == null) return null
return if (isWriteable()) { return if (isWriteable()) {
if (event is PrivateDmEvent) { when {
privateDMDecryptionCache.cachedDM(event) event is PrivateDmEvent -> privateDMDecryptionCache.cachedDM(event)
} else if (event is LnZapRequestEvent && event.isPrivateZap()) { event is LnZapRequestEvent && event.isPrivateZap() -> privateZapsDecryptionCache.cachedPrivateZap(event)?.content
privateZapsDecryptionCache.cachedPrivateZap(event)?.content event is DraftWrapEvent -> draftsDecryptionCache.preCachedDraft(event)?.content
} else if (event is DraftWrapEvent) { else -> event.content
draftsDecryptionCache.preCachedDraft(event)?.content
} else {
event.content
} }
} else { } else {
event.content event.content
@@ -2875,9 +2872,12 @@ class Account(
suspend fun decryptContent(note: Note): String? { suspend fun decryptContent(note: Note): String? {
val event = note.event val event = note.event
return if (event is PrivateDmEvent && isWriteable()) { return when {
event is PrivateDmEvent && isWriteable() -> {
privateDMDecryptionCache.decryptDM(event) privateDMDecryptionCache.decryptDM(event)
} else if (event is LnZapRequestEvent && isWriteable()) { }
event is LnZapRequestEvent && isWriteable() -> {
if (event.isPrivateZap()) { if (event.isPrivateZap()) {
if (isWriteable()) { if (isWriteable()) {
privateZapsDecryptionCache.decryptPrivateZap(event)?.content privateZapsDecryptionCache.decryptPrivateZap(event)?.content
@@ -2887,12 +2887,17 @@ class Account(
} else { } else {
event.content event.content
} }
} else if (event is DraftWrapEvent && isWriteable()) { }
event is DraftWrapEvent && isWriteable() -> {
draftsDecryptionCache.cachedDraft(event)?.content draftsDecryptionCache.cachedDraft(event)?.content
} else { }
else -> {
event?.content event?.content
} }
} }
}
suspend fun decryptZapOrNull(event: LnZapRequestEvent): LnZapPrivateEvent? = if (event.isPrivateZap() && isWriteable()) privateZapsDecryptionCache.decryptPrivateZap(event) else null suspend fun decryptZapOrNull(event: LnZapRequestEvent): LnZapPrivateEvent? = if (event.isPrivateZap() && isWriteable()) privateZapsDecryptionCache.decryptPrivateZap(event) else null
@@ -88,7 +88,8 @@ class ZapPaymentHandler(
val zapSplitSetup = noteEvent?.zapSplitSetup() val zapSplitSetup = noteEvent?.zapSplitSetup()
val unverifiedZapsToSend = val unverifiedZapsToSend =
if (!zapSplitSetup.isNullOrEmpty()) { when {
!zapSplitSetup.isNullOrEmpty() -> {
zapSplitSetup.map { setup -> zapSplitSetup.map { setup ->
when (setup) { when (setup) {
is ZapSplitSetupLnAddress -> { is ZapSplitSetupLnAddress -> {
@@ -109,13 +110,17 @@ class ZapPaymentHandler(
} }
} }
} }
} else if (noteEvent is LiveActivitiesEvent && noteEvent.hasHost()) { }
noteEvent is LiveActivitiesEvent && noteEvent.hasHost() -> {
noteEvent.hosts().map { noteEvent.hosts().map {
val user = LocalCache.checkGetOrCreateUser(it.pubKey) val user = LocalCache.checkGetOrCreateUser(it.pubKey)
val lnAddress = user?.lnAddress() val lnAddress = user?.lnAddress()
UnverifiedZapSplitSetup(lnAddress, relay = it.relayHint, user = user) UnverifiedZapSplitSetup(lnAddress, relay = it.relayHint, user = user)
} }
} else if (noteEvent is AppDefinitionEvent) { }
noteEvent is AppDefinitionEvent -> {
val appLud16 = noteEvent.appMetaData()?.lnAddress() val appLud16 = noteEvent.appMetaData()?.lnAddress()
if (appLud16 != null) { if (appLud16 != null) {
listOf(UnverifiedZapSplitSetup(appLud16)) listOf(UnverifiedZapSplitSetup(appLud16))
@@ -124,13 +129,16 @@ class ZapPaymentHandler(
note.author?.lnAddress() note.author?.lnAddress()
listOf(UnverifiedZapSplitSetup(lud16)) listOf(UnverifiedZapSplitSetup(lud16))
} }
} else { }
else -> {
listOf( listOf(
UnverifiedZapSplitSetup( UnverifiedZapSplitSetup(
note.author?.lnAddress(), note.author?.lnAddress(),
), ),
) )
} }
}
if (showErrorIfNoLnAddress) { if (showErrorIfNoLnAddress) {
val errors = unverifiedZapsToSend.filter { it.lnAddress.isNullOrBlank() } val errors = unverifiedZapsToSend.filter { it.lnAddress.isNullOrBlank() }
@@ -63,19 +63,29 @@ class UrlPreview {
val mimeType = val mimeType =
response.headers["Content-Type"]?.toMediaType() response.headers["Content-Type"]?.toMediaType()
?: throw IllegalArgumentException("Website returned unknown mimetype: ${response.headers["Content-Type"]}") ?: throw IllegalArgumentException("Website returned unknown mimetype: ${response.headers["Content-Type"]}")
if (mimeType.type == "text" && mimeType.subtype == "html") { when {
mimeType.type == "text" && mimeType.subtype == "html" -> {
val metaTags = HtmlParser().parseHtml(response.body.source(), mimeType.charset()) val metaTags = HtmlParser().parseHtml(response.body.source(), mimeType.charset())
val data = OpenGraphParser().extractUrlInfo(metaTags) val data = OpenGraphParser().extractUrlInfo(metaTags)
UrlInfoItem(url, data.title, data.description, data.image, mimeType.toString()) UrlInfoItem(url, data.title, data.description, data.image, mimeType.toString())
} else if (mimeType.type == "image") { }
mimeType.type == "image" -> {
UrlInfoItem(url, image = url, mimeType = mimeType.toString()) UrlInfoItem(url, image = url, mimeType = mimeType.toString())
} else if (mimeType.type == "video") { }
mimeType.type == "video" -> {
UrlInfoItem(url, image = url, mimeType = mimeType.toString()) UrlInfoItem(url, image = url, mimeType = mimeType.toString())
} else if (mimeType.type == "application" && mimeType.subtype == "pdf") { }
mimeType.type == "application" && mimeType.subtype == "pdf" -> {
UrlInfoItem(url, image = url, mimeType = mimeType.toString()) UrlInfoItem(url, image = url, mimeType = mimeType.toString())
} else { }
else -> {
throw IllegalArgumentException("Website returned unknown encoding for previews: $mimeType") throw IllegalArgumentException("Website returned unknown encoding for previews: $mimeType")
} }
}
} else { } else {
throw IllegalArgumentException("Website returned: " + response.code) throw IllegalArgumentException("Website returned: " + response.code)
} }
@@ -70,9 +70,12 @@ class RelayProxyClientConnector(
RelayServiceInfra(torSettings, torConnection, clearConnection, connectivity, torStatus) RelayServiceInfra(torSettings, torConnection, clearConnection, connectivity, torStatus)
}.debounce(100) }.debounce(100)
.onEach { .onEach {
if (it.connectivity is ConnectivityStatus.StartingService) { when {
it.connectivity is ConnectivityStatus.StartingService -> {
// ignore // ignore
} else if (it.connectivity is ConnectivityStatus.Off) { }
it.connectivity is ConnectivityStatus.Off -> {
Log.d("ManageRelayServices") { "Connectivity Off: Pausing Relay Services ${it.connectivity}" } Log.d("ManageRelayServices") { "Connectivity Off: Pausing Relay Services ${it.connectivity}" }
if (client.isActive()) { if (client.isActive()) {
client.disconnect() client.disconnect()
@@ -80,7 +83,9 @@ class RelayProxyClientConnector(
if (it.torStatus is TorServiceStatus.Active) { if (it.torStatus is TorServiceStatus.Active) {
Log.d("ManageRelayServices", "Connectivity off, Tor idle") Log.d("ManageRelayServices", "Connectivity off, Tor idle")
} }
} else if (it.connectivity is ConnectivityStatus.Active && !client.isActive()) { }
it.connectivity is ConnectivityStatus.Active && !client.isActive() -> {
Log.d("ManageRelayServices", "Connectivity On: Resuming Relay Services") Log.d("ManageRelayServices", "Connectivity On: Resuming Relay Services")
if (it.torStatus is TorServiceStatus.Active) { if (it.torStatus is TorServiceStatus.Active) {
@@ -89,13 +94,16 @@ class RelayProxyClientConnector(
// only calls this if the client is not active. Otherwise goes to the else below // only calls this if the client is not active. Otherwise goes to the else below
client.connect() client.connect()
} else { }
else -> {
Log.d("ManageRelayServices", "Relay Services have changed, reconnecting relays that need to") Log.d("ManageRelayServices", "Relay Services have changed, reconnecting relays that need to")
client.reconnect( client.reconnect(
onlyIfChanged = true, onlyIfChanged = true,
ignoreRetryDelays = true, ignoreRetryDelays = true,
) )
} }
}
}.onStart { }.onStart {
Log.d("ManageRelayServices", "Resuming Relay Services") Log.d("ManageRelayServices", "Resuming Relay Services")
client.connect() client.connect()
@@ -136,14 +136,11 @@ class BlossomServerResolver(
url: String, url: String,
mimeType: String?, mimeType: String?,
): OkHttpClient = ): OkHttpClient =
if (mimeType == null) { when {
httpClientBuilder.okHttpClientForPreview(url) mimeType == null -> httpClientBuilder.okHttpClientForPreview(url)
} else if (mimeType.startsWith("audio/") || mimeType.startsWith("video/")) { mimeType.startsWith("audio/") || mimeType.startsWith("video/") -> httpClientBuilder.okHttpClientForVideo(url)
httpClientBuilder.okHttpClientForVideo(url) mimeType.startsWith("image/") -> httpClientBuilder.okHttpClientForImage(url)
} else if (mimeType.startsWith("image/")) { else -> httpClientBuilder.okHttpClientForPreview(url)
httpClientBuilder.okHttpClientForImage(url)
} else {
httpClientBuilder.okHttpClientForPreview(url)
} }
fun canResolve(scheme: String) = scheme == SCHEME fun canResolve(scheme: String) = scheme == SCHEME
@@ -212,7 +212,8 @@ fun EditPostView(
if (myUrlPreview != null) { if (myUrlPreview != null) {
Row(modifier = Modifier.padding(vertical = Size5dp, horizontal = Size10dp)) { Row(modifier = Modifier.padding(vertical = Size5dp, horizontal = Size10dp)) {
if (RichTextParser.isValidURL(myUrlPreview)) { if (RichTextParser.isValidURL(myUrlPreview)) {
if (RichTextParser.isImageUrl(myUrlPreview)) { when {
RichTextParser.isImageUrl(myUrlPreview) -> {
AsyncImage( AsyncImage(
model = myUrlPreview, model = myUrlPreview,
contentDescription = myUrlPreview, contentDescription = myUrlPreview,
@@ -228,7 +229,9 @@ fun EditPostView(
QuoteBorder, QuoteBorder,
), ),
) )
} else if (RichTextParser.isVideoUrl(myUrlPreview)) { }
RichTextParser.isVideoUrl(myUrlPreview) -> {
VideoView( VideoView(
myUrlPreview, myUrlPreview,
mimeType = null, mimeType = null,
@@ -236,9 +239,12 @@ fun EditPostView(
contentScale = ContentScale.FillWidth, contentScale = ContentScale.FillWidth,
accountViewModel = accountViewModel, accountViewModel = accountViewModel,
) )
} else { }
else -> {
LoadUrlPreview(myUrlPreview, myUrlPreview, null, accountViewModel) LoadUrlPreview(myUrlPreview, myUrlPreview, null, accountViewModel)
} }
}
} else if (RichTextParser.startsWithNIP19Scheme(myUrlPreview)) { } else if (RichTextParser.startsWithNIP19Scheme(myUrlPreview)) {
val bgColor = MaterialTheme.colorScheme.background val bgColor = MaterialTheme.colorScheme.background
val backgroundColor = remember { mutableStateOf(bgColor) } val backgroundColor = remember { mutableStateOf(bgColor) }
@@ -188,7 +188,8 @@ class NewMessageTagger(
key = key.removePrefix("@") key = key.removePrefix("@")
try { try {
if (key.startsWith("nsec1", true)) { when {
key.startsWith("nsec1", true) -> {
if (key.length < 63) { if (key.length < 63) {
return null return null
} }
@@ -200,7 +201,9 @@ class NewMessageTagger(
Nip19Parser.uriToRoute(Nip01Crypto.pubKeyCreate(keyB32.bechToBytes()).toNpub()) ?: return null Nip19Parser.uriToRoute(Nip01Crypto.pubKeyCreate(keyB32.bechToBytes()).toNpub()) ?: return null
return DirtyKeyInfo(pubkey, restOfWord.ifEmpty { null }) return DirtyKeyInfo(pubkey, restOfWord.ifEmpty { null })
} else if (key.startsWith("npub1", true)) { }
key.startsWith("npub1", true) -> {
if (key.length < 63) { if (key.length < 63) {
return null return null
} }
@@ -211,7 +214,9 @@ class NewMessageTagger(
val pubkey = Nip19Parser.uriToRoute(keyB32) ?: return null val pubkey = Nip19Parser.uriToRoute(keyB32) ?: return null
return DirtyKeyInfo(pubkey, restOfWord.ifEmpty { null }) return DirtyKeyInfo(pubkey, restOfWord.ifEmpty { null })
} else if (key.startsWith("note1", true)) { }
key.startsWith("note1", true) -> {
if (key.length < 63) { if (key.length < 63) {
return null return null
} }
@@ -222,15 +227,21 @@ class NewMessageTagger(
val noteId = Nip19Parser.uriToRoute(keyB32) ?: return null val noteId = Nip19Parser.uriToRoute(keyB32) ?: return null
return DirtyKeyInfo(noteId, restOfWord.ifEmpty { null }) return DirtyKeyInfo(noteId, restOfWord.ifEmpty { null })
} else if (key.startsWith("nprofile", true)) { }
key.startsWith("nprofile", true) -> {
val pubkeyRelay = Nip19Parser.uriToRoute(key) ?: return null val pubkeyRelay = Nip19Parser.uriToRoute(key) ?: return null
return DirtyKeyInfo(pubkeyRelay, pubkeyRelay.additionalChars) return DirtyKeyInfo(pubkeyRelay, pubkeyRelay.additionalChars)
} else if (key.startsWith("nevent1", true)) { }
key.startsWith("nevent1", true) -> {
val noteRelayId = Nip19Parser.uriToRoute(key) ?: return null val noteRelayId = Nip19Parser.uriToRoute(key) ?: return null
return DirtyKeyInfo(noteRelayId, noteRelayId.additionalChars) return DirtyKeyInfo(noteRelayId, noteRelayId.additionalChars)
} else if (key.startsWith("naddr1", true)) { }
key.startsWith("naddr1", true) -> {
val address = Nip19Parser.uriToRoute(key) ?: return null val address = Nip19Parser.uriToRoute(key) ?: return null
return DirtyKeyInfo( return DirtyKeyInfo(
@@ -238,6 +249,7 @@ class NewMessageTagger(
address.additionalChars, address.additionalChars,
) // no way to know when they address ends and dirt begins ) // no way to know when they address ends and dirt begins
} }
}
} catch (e: Exception) { } catch (e: Exception) {
if (e is CancellationException) throw e if (e is CancellationException) throw e
e.printStackTrace() e.printStackTrace()
@@ -113,7 +113,8 @@ fun ShowImageGallery(
media: SelectedMedia, media: SelectedMedia,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
) { ) {
if (media.isImage() == true) { when {
media.isImage() == true -> {
AsyncImage( AsyncImage(
model = media.uri.toString(), model = media.uri.toString(),
contentDescription = media.uri.toString(), contentDescription = media.uri.toString(),
@@ -123,17 +124,23 @@ fun ShowImageGallery(
.fillMaxWidth() .fillMaxWidth()
.windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp)), .windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp)),
) )
} else if (media.isAudio() == true) { }
media.isAudio() == true -> {
FilePreviewPlaceholder( FilePreviewPlaceholder(
icon = MaterialSymbols.AudioFile, icon = MaterialSymbols.AudioFile,
label = media.mimeType ?: "audio/*", label = media.mimeType ?: "audio/*",
) )
} else if (media.isDocument()) { }
media.isDocument() -> {
FilePreviewPlaceholder( FilePreviewPlaceholder(
icon = MaterialSymbols.PictureAsPdf, icon = MaterialSymbols.PictureAsPdf,
label = media.mimeType ?: "application/pdf", label = media.mimeType ?: "application/pdf",
) )
} else if (media.isVideo() == true && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { }
media.isVideo() == true && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
var bitmap by remember { mutableStateOf<Bitmap?>(null) } var bitmap by remember { mutableStateOf<Bitmap?>(null) }
val context = LocalContext.current val context = LocalContext.current
@@ -166,7 +173,9 @@ fun ShowImageGallery(
accountViewModel = accountViewModel, accountViewModel = accountViewModel,
) )
} }
} else { }
else -> {
VideoView( VideoView(
videoUri = media.uri.toString(), videoUri = media.uri.toString(),
mimeType = media.mimeType, mimeType = media.mimeType,
@@ -176,6 +185,7 @@ fun ShowImageGallery(
) )
} }
} }
}
@Composable @Composable
fun ShowImageUploadItem( fun ShowImageUploadItem(
@@ -95,7 +95,8 @@ fun RenderLoaded(
callbackUri: String? = null, callbackUri: String? = null,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
) { ) {
if (state.previewInfo.mimeType.startsWith("image")) { when {
state.previewInfo.mimeType.startsWith("image") -> {
Box(modifier = HalfVertPadding) { Box(modifier = HalfVertPadding) {
ZoomableContentView( ZoomableContentView(
content = MediaUrlImage(url, uri = callbackUri), content = MediaUrlImage(url, uri = callbackUri),
@@ -104,7 +105,9 @@ fun RenderLoaded(
accountViewModel = accountViewModel, accountViewModel = accountViewModel,
) )
} }
} else if (state.previewInfo.mimeType.startsWith("video")) { }
state.previewInfo.mimeType.startsWith("video") -> {
Box(modifier = HalfVertPadding) { Box(modifier = HalfVertPadding) {
ZoomableContentView( ZoomableContentView(
content = MediaUrlVideo(url, uri = callbackUri), content = MediaUrlVideo(url, uri = callbackUri),
@@ -113,7 +116,9 @@ fun RenderLoaded(
accountViewModel = accountViewModel, accountViewModel = accountViewModel,
) )
} }
} else if (state.previewInfo.mimeType.startsWith("application/pdf")) { }
state.previewInfo.mimeType.startsWith("application/pdf") -> {
Box(modifier = HalfVertPadding) { Box(modifier = HalfVertPadding) {
ZoomableContentView( ZoomableContentView(
content = MediaUrlPdf(url, uri = callbackUri, mimeType = state.previewInfo.mimeType), content = MediaUrlPdf(url, uri = callbackUri, mimeType = state.previewInfo.mimeType),
@@ -122,7 +127,10 @@ fun RenderLoaded(
accountViewModel = accountViewModel, accountViewModel = accountViewModel,
) )
} }
} else { }
else -> {
UrlPreviewCard(url, state.previewInfo) UrlPreviewCard(url, state.previewInfo)
} }
} }
}
@@ -293,17 +293,22 @@ private fun handleZapClick(
val choices = zapAmountChoices ?: accountViewModel.zapAmountChoices() val choices = zapAmountChoices ?: accountViewModel.zapAmountChoices()
if (choices.isEmpty()) { when {
choices.isEmpty() -> {
accountViewModel.toastManager.toast( accountViewModel.toastManager.toast(
stringRes(context, R.string.error_dialog_zap_error), stringRes(context, R.string.error_dialog_zap_error),
stringRes(context, R.string.no_zap_amount_setup_long_press_to_change), stringRes(context, R.string.no_zap_amount_setup_long_press_to_change),
) )
} else if (!accountViewModel.isWriteable()) { }
!accountViewModel.isWriteable() -> {
accountViewModel.toastManager.toast( accountViewModel.toastManager.toast(
stringRes(context, R.string.error_dialog_zap_error), stringRes(context, R.string.error_dialog_zap_error),
stringRes(context, R.string.login_with_a_private_key_to_be_able_to_send_zaps), stringRes(context, R.string.login_with_a_private_key_to_be_able_to_send_zaps),
) )
} else if (choices.size == 1) { }
choices.size == 1 -> {
val amount = choices.first() val amount = choices.first()
if (amount > 1100 || zapAmountChoices != null) { if (amount > 1100 || zapAmountChoices != null) {
@@ -322,7 +327,9 @@ private fun handleZapClick(
} else { } else {
onMultipleChoices(listOf(1000L, 5_000L, 10_000L)) onMultipleChoices(listOf(1000L, 5_000L, 10_000L))
} }
} else { }
else -> {
if (choices.any { it > 1100 } || zapAmountChoices != null) { if (choices.any { it > 1100 } || zapAmountChoices != null) {
onMultipleChoices(choices) onMultipleChoices(choices)
} else { } else {
@@ -330,3 +337,4 @@ private fun handleZapClick(
} }
} }
} }
}
@@ -67,9 +67,12 @@ fun WatchBlockAndReport(
mutableStateOf(false) mutableStateOf(false)
} }
if (showAnyway.value) { when {
showAnyway.value -> {
normalNote(true) normalNote(true)
} else if (!isHidden.isPostHidden) { }
!isHidden.isPostHidden -> {
if (isHidden.isAcceptable) { if (isHidden.isAcceptable) {
normalNote(isHidden.canPreview) normalNote(isHidden.canPreview)
} else { } else {
@@ -82,10 +85,13 @@ fun WatchBlockAndReport(
onClick = { showAnyway.value = true }, onClick = { showAnyway.value = true },
) )
} }
} else if (showHiddenWarning) { }
showHiddenWarning -> {
// if it is a quoted or boosted note, how the hidden warning. // if it is a quoted or boosted note, how the hidden warning.
HiddenNoteByMe { HiddenNoteByMe {
showAnyway.value = true showAnyway.value = true
} }
} }
} }
}
@@ -293,7 +293,8 @@ fun DisplayStatusInner(
) )
} }
if (url != null) { when {
url != null -> {
val uri = LocalUriHandler.current val uri = LocalUriHandler.current
Spacer(modifier = StdHorzSpacer) Spacer(modifier = StdHorzSpacer)
IconButton( IconButton(
@@ -307,7 +308,9 @@ fun DisplayStatusInner(
tint = MaterialTheme.colorScheme.lessImportantLink, tint = MaterialTheme.colorScheme.lessImportantLink,
) )
} }
} else if (nostrATag != null) { }
nostrATag != null -> {
LoadAddressableNote(nostrATag, accountViewModel) { note -> LoadAddressableNote(nostrATag, accountViewModel) { note ->
if (note != null) { if (note != null) {
Spacer(modifier = StdHorzSpacer) Spacer(modifier = StdHorzSpacer)
@@ -329,7 +332,9 @@ fun DisplayStatusInner(
} }
} }
} }
} else if (nostrETag != null) { }
nostrETag != null -> {
LoadNote(baseNoteHex = nostrETag.eventId, accountViewModel) { LoadNote(baseNoteHex = nostrETag.eventId, accountViewModel) {
if (it != null) { if (it != null) {
Spacer(modifier = StdHorzSpacer) Spacer(modifier = StdHorzSpacer)
@@ -351,7 +356,9 @@ fun DisplayStatusInner(
} }
} }
} }
} else if (nostrPTag != null) { }
nostrPTag != null -> {
LoadUser(baseUserHex = nostrPTag, accountViewModel) { user -> LoadUser(baseUserHex = nostrPTag, accountViewModel) { user ->
if (user != null) { if (user != null) {
Spacer(modifier = StdHorzSpacer) Spacer(modifier = StdHorzSpacer)
@@ -370,6 +377,7 @@ fun DisplayStatusInner(
} }
} }
} }
}
@Composable @Composable
fun ObserveAndDisplayNIP05( fun ObserveAndDisplayNIP05(
@@ -116,14 +116,11 @@ val graspLink = { graspNumber: String ->
val externalLinkForNote = { note: Note -> val externalLinkForNote = { note: Note ->
if (note is AddressableNote) { if (note is AddressableNote) {
if (note.event?.bountyBaseReward() != null) { when {
"https://nostrbounties.com/b/${note.toNAddr()}" note.event?.bountyBaseReward() != null -> "https://nostrbounties.com/b/${note.toNAddr()}"
} else if (note.event is PeopleListEvent) { note.event is PeopleListEvent -> "https://listr.lol/a/${note.toNAddr()}"
"https://listr.lol/a/${note.toNAddr()}" note.event is FollowListEvent -> "https://following.space/d/${note.address.dTag}?p=${note.address.pubKeyHex}"
} else if (note.event is FollowListEvent) { else -> njumpLink(note.toNAddr())
"https://following.space/d/${note.address.dTag}?p=${note.address.pubKeyHex}"
} else {
njumpLink(note.toNAddr())
} }
} else { } else {
njumpLink(note.toNEvent()) njumpLink(note.toNEvent())
@@ -1146,22 +1146,30 @@ private fun likeClick(
} }
val choices = accountViewModel.reactionChoices() val choices = accountViewModel.reactionChoices()
if (choices.isEmpty()) { when {
choices.isEmpty() -> {
accountViewModel.toastManager.toast( accountViewModel.toastManager.toast(
R.string.no_reactions_setup, R.string.no_reactions_setup,
R.string.no_reaction_type_setup_long_press_to_change, R.string.no_reaction_type_setup_long_press_to_change,
) )
} else if (!accountViewModel.isWriteable()) { }
!accountViewModel.isWriteable() -> {
accountViewModel.toastManager.toast( accountViewModel.toastManager.toast(
R.string.read_only_user, R.string.read_only_user,
R.string.login_with_a_private_key_to_like_posts, R.string.login_with_a_private_key_to_like_posts,
) )
} else if (choices.size == 1) { }
choices.size == 1 -> {
onWantsToSignReaction() onWantsToSignReaction()
} else if (choices.size > 1) { }
choices.size > 1 -> {
onMultipleChoices() onMultipleChoices()
} }
} }
}
@Composable @Composable
@OptIn(ExperimentalFoundationApi::class, ExperimentalUuidApi::class) @OptIn(ExperimentalFoundationApi::class, ExperimentalUuidApi::class)
@@ -1369,14 +1377,19 @@ fun zapClick(
val choices = accountViewModel.zapAmountChoices() val choices = accountViewModel.zapAmountChoices()
if (choices.isEmpty()) { when {
choices.isEmpty() -> {
onCustomAmount() onCustomAmount()
} else if (!accountViewModel.isWriteable()) { }
!accountViewModel.isWriteable() -> {
accountViewModel.toastManager.toast( accountViewModel.toastManager.toast(
R.string.error_dialog_zap_error, R.string.error_dialog_zap_error,
R.string.login_with_a_private_key_to_be_able_to_send_zaps, R.string.login_with_a_private_key_to_be_able_to_send_zaps,
) )
} else if (choices.size == 1) { }
choices.size == 1 -> {
onZapStarts() onZapStarts()
accountViewModel.zap( accountViewModel.zap(
baseNote, baseNote,
@@ -1388,10 +1401,13 @@ fun zapClick(
onProgress = { onZappingProgress(it) }, onProgress = { onZappingProgress(it) },
onPayViaIntent = onPayViaIntent, onPayViaIntent = onPayViaIntent,
) )
} else if (choices.size > 1) { }
choices.size > 1 -> {
onMultipleChoices() onMultipleChoices()
} }
} }
}
@Composable @Composable
private fun TwoStageZapProgressIcon( private fun TwoStageZapProgressIcon(
@@ -56,7 +56,8 @@ fun timeAgo(
val timeDifference = TimeUtils.now() - time val timeDifference = TimeUtils.now() - time
return if (timeDifference > TimeUtils.ONE_YEAR) { return when {
timeDifference > TimeUtils.ONE_YEAR -> {
// Dec 12, 2022 // Dec 12, 2022
if (locale != Locale.getDefault()) { if (locale != Locale.getDefault()) {
@@ -66,7 +67,9 @@ fun timeAgo(
} }
prefix + yearFormatter.format(time * 1000) prefix + yearFormatter.format(time * 1000)
} else if (timeDifference > TimeUtils.ONE_MONTH) { }
timeDifference > TimeUtils.ONE_MONTH -> {
// Dec 12 // Dec 12
if (locale != Locale.getDefault()) { if (locale != Locale.getDefault()) {
locale = Locale.getDefault() locale = Locale.getDefault()
@@ -75,17 +78,25 @@ fun timeAgo(
} }
prefix + monthFormatter.format(time * 1000) prefix + monthFormatter.format(time * 1000)
} else if (timeDifference > TimeUtils.ONE_DAY) { }
// 2 days
timeDifference > TimeUtils.ONE_DAY -> {
prefix + (timeDifference / TimeUtils.ONE_DAY).toString() + stringRes(context, days) prefix + (timeDifference / TimeUtils.ONE_DAY).toString() + stringRes(context, days)
} else if (timeDifference > TimeUtils.ONE_HOUR) { }
timeDifference > TimeUtils.ONE_HOUR -> {
prefix + (timeDifference / TimeUtils.ONE_HOUR).toString() + stringRes(context, hours) prefix + (timeDifference / TimeUtils.ONE_HOUR).toString() + stringRes(context, hours)
} else if (timeDifference > TimeUtils.ONE_MINUTE) { }
timeDifference > TimeUtils.ONE_MINUTE -> {
prefix + (timeDifference / TimeUtils.ONE_MINUTE).toString() + stringRes(context, minutes) prefix + (timeDifference / TimeUtils.ONE_MINUTE).toString() + stringRes(context, minutes)
} else { }
else -> {
prefix + stringRes(context, seconds) prefix + stringRes(context, seconds)
} }
} }
}
fun timeAgoNoDot( fun timeAgoNoDot(
time: Long?, time: Long?,
@@ -96,7 +107,8 @@ fun timeAgoNoDot(
val timeDifference = TimeUtils.now() - time val timeDifference = TimeUtils.now() - time
return if (timeDifference > TimeUtils.ONE_YEAR) { return when {
timeDifference > TimeUtils.ONE_YEAR -> {
// Dec 12, 2022 // Dec 12, 2022
if (locale != Locale.getDefault()) { if (locale != Locale.getDefault()) {
@@ -106,7 +118,9 @@ fun timeAgoNoDot(
} }
yearFormatter.format(time * 1000) yearFormatter.format(time * 1000)
} else if (timeDifference > TimeUtils.ONE_MONTH) { }
timeDifference > TimeUtils.ONE_MONTH -> {
// Dec 12 // Dec 12
if (locale != Locale.getDefault()) { if (locale != Locale.getDefault()) {
locale = Locale.getDefault() locale = Locale.getDefault()
@@ -115,17 +129,25 @@ fun timeAgoNoDot(
} }
monthFormatter.format(time * 1000) monthFormatter.format(time * 1000)
} else if (timeDifference > TimeUtils.ONE_DAY) { }
// 2 days
timeDifference > TimeUtils.ONE_DAY -> {
(timeDifference / TimeUtils.ONE_DAY).toString() + stringRes(context, R.string.d) (timeDifference / TimeUtils.ONE_DAY).toString() + stringRes(context, R.string.d)
} else if (timeDifference > TimeUtils.ONE_HOUR) { }
timeDifference > TimeUtils.ONE_HOUR -> {
(timeDifference / TimeUtils.ONE_HOUR).toString() + stringRes(context, R.string.h) (timeDifference / TimeUtils.ONE_HOUR).toString() + stringRes(context, R.string.h)
} else if (timeDifference > TimeUtils.ONE_MINUTE) { }
timeDifference > TimeUtils.ONE_MINUTE -> {
(timeDifference / TimeUtils.ONE_MINUTE).toString() + stringRes(context, R.string.m) (timeDifference / TimeUtils.ONE_MINUTE).toString() + stringRes(context, R.string.m)
} else { }
else -> {
stringRes(context, R.string.now) stringRes(context, R.string.now)
} }
} }
}
fun timeAgoNoDotNoDay( fun timeAgoNoDotNoDay(
time: Long?, time: Long?,
@@ -136,7 +158,8 @@ fun timeAgoNoDotNoDay(
val timeDifference = TimeUtils.now() - time val timeDifference = TimeUtils.now() - time
return if (timeDifference > TimeUtils.ONE_YEAR) { return when {
timeDifference > TimeUtils.ONE_YEAR -> {
// Dec 12, 2022 // Dec 12, 2022
if (locale != Locale.getDefault()) { if (locale != Locale.getDefault()) {
@@ -146,7 +169,9 @@ fun timeAgoNoDotNoDay(
} }
yearNoDayFormatter.format(time * 1000) yearNoDayFormatter.format(time * 1000)
} else if (timeDifference > TimeUtils.ONE_MONTH) { }
timeDifference > TimeUtils.ONE_MONTH -> {
// Dec 12 // Dec 12
if (locale != Locale.getDefault()) { if (locale != Locale.getDefault()) {
locale = Locale.getDefault() locale = Locale.getDefault()
@@ -155,17 +180,25 @@ fun timeAgoNoDotNoDay(
} }
monthNoDayFormatter.format(time * 1000) monthNoDayFormatter.format(time * 1000)
} else if (timeDifference > TimeUtils.ONE_DAY) { }
// 2 days
timeDifference > TimeUtils.ONE_DAY -> {
(timeDifference / TimeUtils.ONE_DAY).toString() + stringRes(context, R.string.d) (timeDifference / TimeUtils.ONE_DAY).toString() + stringRes(context, R.string.d)
} else if (timeDifference > TimeUtils.ONE_HOUR) { }
timeDifference > TimeUtils.ONE_HOUR -> {
(timeDifference / TimeUtils.ONE_HOUR).toString() + stringRes(context, R.string.h) (timeDifference / TimeUtils.ONE_HOUR).toString() + stringRes(context, R.string.h)
} else if (timeDifference > TimeUtils.ONE_MINUTE) { }
timeDifference > TimeUtils.ONE_MINUTE -> {
(timeDifference / TimeUtils.ONE_MINUTE).toString() + stringRes(context, R.string.m) (timeDifference / TimeUtils.ONE_MINUTE).toString() + stringRes(context, R.string.m)
} else { }
else -> {
stringRes(context, R.string.now) stringRes(context, R.string.now)
} }
} }
}
fun timeAheadNoDot( fun timeAheadNoDot(
time: Long?, time: Long?,
@@ -176,7 +209,8 @@ fun timeAheadNoDot(
val timeDifference = time - TimeUtils.now() val timeDifference = time - TimeUtils.now()
return if (timeDifference > TimeUtils.ONE_YEAR) { return when {
timeDifference > TimeUtils.ONE_YEAR -> {
// Dec 12, 2022 // Dec 12, 2022
if (locale != Locale.getDefault()) { if (locale != Locale.getDefault()) {
@@ -186,7 +220,9 @@ fun timeAheadNoDot(
} }
yearFormatter.format(time * 1000) yearFormatter.format(time * 1000)
} else if (timeDifference > TimeUtils.ONE_MONTH) { }
timeDifference > TimeUtils.ONE_MONTH -> {
// Dec 12 // Dec 12
if (locale != Locale.getDefault()) { if (locale != Locale.getDefault()) {
locale = Locale.getDefault() locale = Locale.getDefault()
@@ -195,17 +231,25 @@ fun timeAheadNoDot(
} }
monthFormatter.format(time * 1000) monthFormatter.format(time * 1000)
} else if (timeDifference > TimeUtils.ONE_DAY) { }
// 2 days
timeDifference > TimeUtils.ONE_DAY -> {
round(timeDifference / TimeUtils.ONE_DAY.toFloat()).toInt().toString() + stringRes(context, R.string.d) round(timeDifference / TimeUtils.ONE_DAY.toFloat()).toInt().toString() + stringRes(context, R.string.d)
} else if (timeDifference > TimeUtils.ONE_HOUR) { }
timeDifference > TimeUtils.ONE_HOUR -> {
round(timeDifference / TimeUtils.ONE_HOUR.toFloat()).toInt().toString() + stringRes(context, R.string.h) round(timeDifference / TimeUtils.ONE_HOUR.toFloat()).toInt().toString() + stringRes(context, R.string.h)
} else if (timeDifference > TimeUtils.ONE_MINUTE) { }
timeDifference > TimeUtils.ONE_MINUTE -> {
round(timeDifference / TimeUtils.ONE_MINUTE.toFloat()).toInt().toString() + stringRes(context, R.string.m) round(timeDifference / TimeUtils.ONE_MINUTE.toFloat()).toInt().toString() + stringRes(context, R.string.m)
} else { }
else -> {
stringRes(context, R.string.now) stringRes(context, R.string.now)
} }
} }
}
fun dateFormatter( fun dateFormatter(
time: Long?, time: Long?,
@@ -547,32 +547,39 @@ fun ZapVote(
interactionSource = remember { MutableInteractionSource() }, interactionSource = remember { MutableInteractionSource() },
indication = ripple24dp, indication = ripple24dp,
onClick = { onClick = {
if (!accountViewModel.isWriteable()) { when {
!accountViewModel.isWriteable() -> {
accountViewModel.toastManager.toast( accountViewModel.toastManager.toast(
R.string.read_only_user, R.string.read_only_user,
R.string.login_with_a_private_key_to_be_able_to_send_zaps, R.string.login_with_a_private_key_to_be_able_to_send_zaps,
) )
} else if (pollViewModel.isPollClosed()) { }
pollViewModel.isPollClosed() -> {
accountViewModel.toastManager.toast( accountViewModel.toastManager.toast(
R.string.poll_unable_to_vote, R.string.poll_unable_to_vote,
R.string.poll_is_closed_explainer, R.string.poll_is_closed_explainer,
) )
} else if (isLoggedUser) { }
isLoggedUser -> {
accountViewModel.toastManager.toast( accountViewModel.toastManager.toast(
R.string.poll_unable_to_vote, R.string.poll_unable_to_vote,
R.string.poll_author_no_vote, R.string.poll_author_no_vote,
) )
} else if (pollViewModel.isVoteAmountAtomic() && poolOption.zappedByLoggedIn.value) { }
pollViewModel.isVoteAmountAtomic() && poolOption.zappedByLoggedIn.value -> {
// only allow one vote per option when min==max, i.e. atomic vote amount specified // only allow one vote per option when min==max, i.e. atomic vote amount specified
accountViewModel.toastManager.toast( accountViewModel.toastManager.toast(
R.string.poll_unable_to_vote, R.string.poll_unable_to_vote,
R.string.one_vote_per_user_on_atomic_votes, R.string.one_vote_per_user_on_atomic_votes,
) )
return@combinedClickable return@combinedClickable
} else if ( }
accountViewModel.zapAmountChoices().size == 1 && accountViewModel.zapAmountChoices().size == 1 &&
pollViewModel.isValidInputVoteAmount(accountViewModel.zapAmountChoices().first()) pollViewModel.isValidInputVoteAmount(accountViewModel.zapAmountChoices().first()) -> {
) {
accountViewModel.zap( accountViewModel.zap(
baseNote, baseNote,
accountViewModel.zapAmountChoices().first() * 1000, accountViewModel.zapAmountChoices().first() * 1000,
@@ -598,9 +605,12 @@ fun ZapVote(
} }
}, },
) )
} else { }
else -> {
wantsToZap = true wantsToZap = true
} }
}
}, },
), ),
) { ) {
@@ -138,14 +138,11 @@ class PollNoteViewModel : ViewModel() {
} == true } == true
fun voteAmountPlaceHolderText(sats: String): String = fun voteAmountPlaceHolderText(sats: String): String =
if (valueMinimum == null && valueMaximum == null) { when {
sats valueMinimum == null && valueMaximum == null -> sats
} else if (valueMinimum == null) { valueMinimum == null -> "1—$valueMaximum $sats"
"1—$valueMaximum $sats" valueMaximum == null -> ">$valueMinimum $sats"
} else if (valueMaximum == null) { else -> "$valueMinimum$valueMaximum $sats"
">$valueMinimum $sats"
} else {
"$valueMinimum$valueMaximum $sats"
} }
fun inputVoteAmountLong(textAmount: String) = fun inputVoteAmountLong(textAmount: String) =
@@ -160,48 +157,68 @@ class PollNoteViewModel : ViewModel() {
} }
fun isValidInputVoteAmount(amount: BigDecimal?): Boolean { fun isValidInputVoteAmount(amount: BigDecimal?): Boolean {
if (amount == null) { when {
amount == null -> {
return false return false
} else if (valueMinimum == null && valueMaximum == null) { }
valueMinimum == null && valueMaximum == null -> {
if (amount > BigDecimal.ZERO) { if (amount > BigDecimal.ZERO) {
return true return true
} }
} else if (valueMinimum == null) { }
valueMinimum == null -> {
if (amount > BigDecimal.ZERO && amount <= valueMaximumBD!!) { if (amount > BigDecimal.ZERO && amount <= valueMaximumBD!!) {
return true return true
} }
} else if (valueMaximum == null) { }
valueMaximum == null -> {
if (amount >= valueMinimumBD!!) { if (amount >= valueMinimumBD!!) {
return true return true
} }
} else { }
else -> {
if ((valueMinimumBD!! <= amount) && (amount <= valueMaximumBD!!)) { if ((valueMinimumBD!! <= amount) && (amount <= valueMaximumBD!!)) {
return true return true
} }
} }
}
return false return false
} }
fun isValidInputVoteAmount(amount: Long?): Boolean { fun isValidInputVoteAmount(amount: Long?): Boolean {
if (amount == null) { when {
amount == null -> {
return false return false
} else if (valueMinimum == null && valueMaximum == null) { }
valueMinimum == null && valueMaximum == null -> {
if (amount > 0) { if (amount > 0) {
return true return true
} }
} else if (valueMinimum == null) { }
valueMinimum == null -> {
if (amount > 0 && amount <= valueMaximum!!) { if (amount > 0 && amount <= valueMaximum!!) {
return true return true
} }
} else if (valueMaximum == null) { }
valueMaximum == null -> {
if (amount >= valueMinimum!!) { if (amount >= valueMinimum!!) {
return true return true
} }
} else { }
else -> {
if ((valueMinimum!! <= amount) && (amount <= valueMaximum!!)) { if ((valueMinimum!! <= amount) && (amount <= valueMaximum!!)) {
return true return true
} }
} }
}
return false return false
} }
@@ -60,15 +60,19 @@ fun PreviewUrl(
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
) { ) {
if (RichTextParser.isValidURL(myUrlPreview)) { when {
if (RichTextParser.isImageUrl(myUrlPreview)) { RichTextParser.isValidURL(myUrlPreview) -> {
when {
RichTextParser.isImageUrl(myUrlPreview) -> {
AsyncImage( AsyncImage(
model = myUrlPreview, model = myUrlPreview,
contentDescription = myUrlPreview, contentDescription = myUrlPreview,
contentScale = ContentScale.FillHeight, contentScale = ContentScale.FillHeight,
modifier = Modifier.fillMaxHeight().aspectRatio(1f), modifier = Modifier.fillMaxHeight().aspectRatio(1f),
) )
} else if (RichTextParser.isVideoUrl(myUrlPreview)) { }
RichTextParser.isVideoUrl(myUrlPreview) -> {
VideoView( VideoView(
myUrlPreview, myUrlPreview,
mimeType = null, mimeType = null,
@@ -77,10 +81,15 @@ fun PreviewUrl(
contentScale = ContentScale.FillHeight, contentScale = ContentScale.FillHeight,
accountViewModel = accountViewModel, accountViewModel = accountViewModel,
) )
} else { }
else -> {
MyLoadUrlPreviewDirect(myUrlPreview, myUrlPreview, accountViewModel) MyLoadUrlPreviewDirect(myUrlPreview, myUrlPreview, accountViewModel)
} }
} else if (RichTextParser.startsWithNIP19Scheme(myUrlPreview)) { }
}
RichTextParser.startsWithNIP19Scheme(myUrlPreview) -> {
val bgColor = MaterialTheme.colorScheme.background val bgColor = MaterialTheme.colorScheme.background
val backgroundColor = remember { mutableStateOf(bgColor) } val backgroundColor = remember { mutableStateOf(bgColor) }
@@ -92,10 +101,13 @@ fun PreviewUrl(
accountViewModel = accountViewModel, accountViewModel = accountViewModel,
nav = nav, nav = nav,
) )
} else if (RichTextParser.isUrlWithoutScheme(myUrlPreview)) { }
RichTextParser.isUrlWithoutScheme(myUrlPreview) -> {
MyLoadUrlPreviewDirect("https://$myUrlPreview", myUrlPreview, accountViewModel) MyLoadUrlPreviewDirect("https://$myUrlPreview", myUrlPreview, accountViewModel)
} }
} }
}
@Composable @Composable
fun PreviewUrlFillWidth( fun PreviewUrlFillWidth(
@@ -104,14 +116,17 @@ fun PreviewUrlFillWidth(
nav: INav, nav: INav,
) { ) {
if (RichTextParser.isValidURL(myUrlPreview)) { if (RichTextParser.isValidURL(myUrlPreview)) {
if (RichTextParser.isImageUrl(myUrlPreview)) { when {
RichTextParser.isImageUrl(myUrlPreview) -> {
AsyncImage( AsyncImage(
model = myUrlPreview, model = myUrlPreview,
contentDescription = myUrlPreview, contentDescription = myUrlPreview,
contentScale = ContentScale.FillWidth, contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxHeight().aspectRatio(1f), modifier = Modifier.fillMaxHeight().aspectRatio(1f),
) )
} else if (RichTextParser.isVideoUrl(myUrlPreview)) { }
RichTextParser.isVideoUrl(myUrlPreview) -> {
VideoView( VideoView(
myUrlPreview, myUrlPreview,
mimeType = null, mimeType = null,
@@ -120,9 +135,12 @@ fun PreviewUrlFillWidth(
contentScale = ContentScale.FillWidth, contentScale = ContentScale.FillWidth,
accountViewModel = accountViewModel, accountViewModel = accountViewModel,
) )
} else { }
else -> {
MyLoadUrlPreviewDirectFillWidth(myUrlPreview, myUrlPreview, accountViewModel) MyLoadUrlPreviewDirectFillWidth(myUrlPreview, myUrlPreview, accountViewModel)
} }
}
} else if (RichTextParser.startsWithNIP19Scheme(myUrlPreview)) { } else if (RichTextParser.startsWithNIP19Scheme(myUrlPreview)) {
val bgColor = MaterialTheme.colorScheme.background val bgColor = MaterialTheme.colorScheme.background
val backgroundColor = remember { mutableStateOf(bgColor) } val backgroundColor = remember { mutableStateOf(bgColor) }
@@ -92,7 +92,8 @@ class UserSuggestionState(
} else { } else {
null null
} }
if (nip05 != null) { when {
nip05 != null -> {
runCatching { runCatching {
nip05Client.get(nip05)?.let { info -> nip05Client.get(nip05)?.let { info ->
val user = account.cache.checkGetOrCreateUser(info.pubkey) val user = account.cache.checkGetOrCreateUser(info.pubkey)
@@ -106,7 +107,9 @@ class UserSuggestionState(
user user
} }
}.getOrNull() }.getOrNull()
} else if (prefix.startsWithAny(userUriPrefixes)) { }
prefix.startsWithAny(userUriPrefixes) -> {
runCatching { runCatching {
Nip19Parser.uriToRoute(prefix)?.entity?.let { parsed -> Nip19Parser.uriToRoute(prefix)?.entity?.let { parsed ->
when (parsed) { when (parsed) {
@@ -132,11 +135,16 @@ class UserSuggestionState(
} }
} }
}.getOrNull() }.getOrNull()
} else if (prefix.length == 64 && Hex.isHex64(prefix)) { }
prefix.length == 64 && Hex.isHex64(prefix) -> {
account.cache.getOrCreateUser(prefix) account.cache.getOrCreateUser(prefix)
} else { }
else -> {
null null
} }
}
} else { } else {
null null
} }
@@ -331,7 +331,8 @@ fun RenderAttestationRequest(
} }
if (quotesLeft > 0) { if (quotesLeft > 0) {
if (aboutAddress != null) { when {
aboutAddress != null -> {
LoadAddressableNote(aboutAddress, accountViewModel) { LoadAddressableNote(aboutAddress, accountViewModel) {
if (it != null) { if (it != null) {
Spacer(modifier = DoubleVertSpacer) Spacer(modifier = DoubleVertSpacer)
@@ -353,7 +354,9 @@ fun RenderAttestationRequest(
) )
} }
} }
} else if (aboutEvent != null) { }
aboutEvent != null -> {
LoadNote(aboutEvent, accountViewModel) { LoadNote(aboutEvent, accountViewModel) {
if (it != null) { if (it != null) {
Spacer(modifier = DoubleVertSpacer) Spacer(modifier = DoubleVertSpacer)
@@ -375,7 +378,9 @@ fun RenderAttestationRequest(
) )
} }
} }
} else if (aboutPubkey != null) { }
aboutPubkey != null -> {
LoadUser(aboutPubkey, accountViewModel) { LoadUser(aboutPubkey, accountViewModel) {
if (it != null) { if (it != null) {
Spacer(modifier = DoubleVertSpacer) Spacer(modifier = DoubleVertSpacer)
@@ -390,6 +395,7 @@ fun RenderAttestationRequest(
} }
} }
} }
}
@OptIn(ExperimentalLayoutApi::class) @OptIn(ExperimentalLayoutApi::class)
@Composable @Composable
@@ -278,24 +278,32 @@ private fun DisplayQuoteAuthor(
} }
} }
if (addressable != null) { when {
addressable != null -> {
addressable?.let { addressable?.let {
DisplayEntryForNote(it, userBase, accountViewModel, nav) DisplayEntryForNote(it, userBase, accountViewModel, nav)
} }
} else if (version != null) { }
version != null -> {
version?.let { version?.let {
DisplayEntryForNote(it, userBase, accountViewModel, nav) DisplayEntryForNote(it, userBase, accountViewModel, nav)
} }
} else if (baseUrl != null) { }
baseUrl != null -> {
val url = "$baseUrl${if (baseUrl.contains("#")) "&" else "#"}:~:text=${Uri.encode(highlightQuote)}" val url = "$baseUrl${if (baseUrl.contains("#")) "&" else "#"}:~:text=${Uri.encode(highlightQuote)}"
DisplayEntryForAUrl(url, userBase, accountViewModel, nav) DisplayEntryForAUrl(url, userBase, accountViewModel, nav)
} else if (userBase != null) { }
userBase != null -> {
userBase?.let { userBase?.let {
DisplayEntryForUser(it, accountViewModel, nav) DisplayEntryForUser(it, accountViewModel, nav)
} }
} }
} }
}
@Composable @Composable
fun DisplayEntryForUser( fun DisplayEntryForUser(
@@ -233,14 +233,11 @@ fun RenderEyeGlassesPrescription(
val isContacts = contactsRightEye != null || contactsLeftEye != null val isContacts = contactsRightEye != null || contactsLeftEye != null
Text( Text(
if (isGlasses && isContacts) { when {
"Vision Prescription" isGlasses && isContacts -> "Vision Prescription"
} else if (isGlasses) { isGlasses -> "Glasses Prescription"
"Glasses Prescription" isContacts -> "Contact Lenses Prescription"
} else if (isContacts) { else -> "Empty Prescription"
"Contact Lenses Prescription"
} else {
"Empty Prescription"
}, },
modifier = Modifier.padding(4.dp).fillMaxWidth(), modifier = Modifier.padding(4.dp).fillMaxWidth(),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
@@ -134,13 +134,16 @@ class AccountSessionManager(
} }
val accountSettings = val accountSettings =
if (loginWithExternalSigner) { when {
loginWithExternalSigner -> {
AccountSettings( AccountSettings(
keyPair = KeyPair(pubKey = pubKeyParsed), keyPair = KeyPair(pubKey = pubKeyParsed),
transientAccount = transientAccount, transientAccount = transientAccount,
externalSignerPackageName = packageName.ifBlank { "com.greenart7c3.nostrsigner" }, externalSignerPackageName = packageName.ifBlank { "com.greenart7c3.nostrsigner" },
) )
} else if (key.startsWith("nsec")) { }
key.startsWith("nsec") -> {
val privHex = val privHex =
decodePrivateKeyAsHexOrNull(key) decodePrivateKeyAsHexOrNull(key)
?: throw Exception("Invalid nsec key") ?: throw Exception("Invalid nsec key")
@@ -148,22 +151,29 @@ class AccountSessionManager(
keyPair = KeyPair(privKey = privHex.hexToByteArray()), keyPair = KeyPair(privKey = privHex.hexToByteArray()),
transientAccount = transientAccount, transientAccount = transientAccount,
) )
} else if (key.contains(" ") && Nip06().isValidMnemonic(key)) { }
key.contains(" ") && Nip06().isValidMnemonic(key) -> {
AccountSettings( AccountSettings(
keyPair = KeyPair(privKey = Nip06().privateKeyFromMnemonic(key)), keyPair = KeyPair(privKey = Nip06().privateKeyFromMnemonic(key)),
transientAccount = transientAccount, transientAccount = transientAccount,
) )
} else if (pubKeyParsed != null) { }
pubKeyParsed != null -> {
AccountSettings( AccountSettings(
keyPair = KeyPair(pubKey = pubKeyParsed), keyPair = KeyPair(pubKey = pubKeyParsed),
transientAccount = transientAccount, transientAccount = transientAccount,
) )
} else { }
else -> {
AccountSettings( AccountSettings(
keyPair = KeyPair(Hex.decode(key)), keyPair = KeyPair(Hex.decode(key)),
transientAccount = transientAccount, transientAccount = transientAccount,
) )
} }
}
localPreferences.setDefaultAccount(accountSettings) localPreferences.setDefaultAccount(accountSettings)
@@ -1404,11 +1404,16 @@ class AccountViewModel(
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
for (note in notes) { for (note in notes) {
val noteEvent = note.event val noteEvent = note.event
if (noteEvent is IsInPublicChatChannel) { when {
noteEvent is IsInPublicChatChannel -> {
account.markAsRead("Channel/${noteEvent.channelId()}", noteEvent.createdAt) account.markAsRead("Channel/${noteEvent.channelId()}", noteEvent.createdAt)
} else if (noteEvent is ChatroomKeyable) { }
noteEvent is ChatroomKeyable -> {
account.markAsRead("Room/${noteEvent.chatroomKey(account.signer.pubKey).hashCode()}", noteEvent.createdAt) account.markAsRead("Room/${noteEvent.chatroomKey(account.signer.pubKey).hashCode()}", noteEvent.createdAt)
} else if (noteEvent is DraftWrapEvent) { }
noteEvent is DraftWrapEvent -> {
val innerEvent = account.draftsDecryptionCache.preCachedDraft(noteEvent) val innerEvent = account.draftsDecryptionCache.preCachedDraft(noteEvent)
if (innerEvent is IsInPublicChatChannel) { if (innerEvent is IsInPublicChatChannel) {
account.markAsRead("Channel/${innerEvent.channelId()}", noteEvent.createdAt) account.markAsRead("Channel/${innerEvent.channelId()}", noteEvent.createdAt)
@@ -1417,6 +1422,7 @@ class AccountViewModel(
} }
} }
} }
}
markHiddenChatroomsAsRead() markHiddenChatroomsAsRead()
} }
@@ -172,15 +172,17 @@ fun NormalChatNote(
remember(note) { remember(note) {
derivedStateOf { derivedStateOf {
val noteEvent = note.event val noteEvent = note.event
if (accountViewModel.isLoggedUser(note.author)) { when {
false // never shows the user's pictures accountViewModel.isLoggedUser(note.author) -> false
} else if (noteEvent is PrivateDmEvent) {
false // one-on-one, never shows it. // never shows the user's pictures
} else if (noteEvent is ChatroomKeyable) { noteEvent is PrivateDmEvent -> false
// one-on-one, never shows it.
// only shows in a group chat. // only shows in a group chat.
noteEvent.chatroomKey(accountViewModel.userProfile().pubkeyHex).users.size > 1 noteEvent is ChatroomKeyable -> noteEvent.chatroomKey(accountViewModel.userProfile().pubkeyHex).users.size > 1
} else {
true else -> true
} }
} }
} }
@@ -735,19 +735,27 @@ class ChatNewMessageViewModel :
fun autocompleteWithUser(item: User) { fun autocompleteWithUser(item: User) {
userSuggestions?.let { userSuggestions -> userSuggestions?.let { userSuggestions ->
if (userSuggestionsMainMessage == UserSuggestionAnchor.MAIN_MESSAGE) { when (userSuggestionsMainMessage) {
UserSuggestionAnchor.MAIN_MESSAGE -> {
val lastWord = message.currentWord() val lastWord = message.currentWord()
userSuggestions.replaceCurrentWord(message, lastWord, item) userSuggestions.replaceCurrentWord(message, lastWord, item)
urlPreviews.update(message.text.toString()) urlPreviews.update(message.text.toString())
} else if (userSuggestionsMainMessage == UserSuggestionAnchor.FORWARD_ZAPS) { }
UserSuggestionAnchor.FORWARD_ZAPS -> {
forwardZapTo.value.addItem(item) forwardZapTo.value.addItem(item)
forwardZapToEditting.value = TextFieldValue("") forwardZapToEditting.value = TextFieldValue("")
} else if (userSuggestionsMainMessage == UserSuggestionAnchor.TO_USERS) { }
UserSuggestionAnchor.TO_USERS -> {
val lastWord = toUsers.currentWord() val lastWord = toUsers.currentWord()
userSuggestions.replaceCurrentWord(toUsers, lastWord, item) userSuggestions.replaceCurrentWord(toUsers, lastWord, item)
updateRoomFromUsersInput() updateRoomFromUsersInput()
} }
else -> {}
}
userSuggestionsMainMessage = null userSuggestionsMainMessage = null
userSuggestions.reset() userSuggestions.reset()
} }
@@ -415,7 +415,8 @@ open class ChannelNewMessageViewModel :
val contentWarningReason = if (wantsToMarkAsSensitive) contentWarningDescription else null val contentWarningReason = if (wantsToMarkAsSensitive) contentWarningDescription else null
val localExpirationDate = if (wantsExpirationDate) expirationDate else null val localExpirationDate = if (wantsExpirationDate) expirationDate else null
return if (channel is PublicChatChannel) { return when {
channel is PublicChatChannel -> {
val replyingToEvent = replyTo.value?.toEventHint<ChannelMessageEvent>() val replyingToEvent = replyTo.value?.toEventHint<ChannelMessageEvent>()
val channelEvent = channel.event val channelEvent = channel.event
@@ -462,7 +463,9 @@ open class ChannelNewMessageViewModel :
imetas(usedAttachments) imetas(usedAttachments)
} }
} }
} else if (channel is LiveActivitiesChannel) { }
channel is LiveActivitiesChannel -> {
val replyingToEvent = replyTo.value?.toEventHint<LiveActivitiesChatMessageEvent>() val replyingToEvent = replyTo.value?.toEventHint<LiveActivitiesChatMessageEvent>()
val activity = channel.info val activity = channel.info
@@ -504,7 +507,9 @@ open class ChannelNewMessageViewModel :
imetas(usedAttachments) imetas(usedAttachments)
} }
} }
} else if (channel is EphemeralChatChannel) { }
channel is EphemeralChatChannel -> {
EphemeralChatEvent.build( EphemeralChatEvent.build(
tagger.message, tagger.message,
channel.roomId.relayUrl, channel.roomId.relayUrl,
@@ -519,10 +524,13 @@ open class ChannelNewMessageViewModel :
emojis(emojis) emojis(emojis)
imetas(usedAttachments) imetas(usedAttachments)
} }
} else { }
else -> {
null null
} }
} }
}
fun findEmoji( fun findEmoji(
message: String, message: String,
@@ -140,19 +140,27 @@ fun RenderContentDVMThumb(
card.amount?.let { card.amount?.let {
var color = Color.DarkGray var color = Color.DarkGray
var amount = it var amount = it
if (card.amount == "free" || card.amount == "0") { when {
card.amount == "free" || card.amount == "0" -> {
color = MaterialTheme.colorScheme.secondary color = MaterialTheme.colorScheme.secondary
amount = "Free" amount = "Free"
} else if (card.amount == "flexible") { }
card.amount == "flexible" -> {
color = MaterialTheme.colorScheme.primaryContainer color = MaterialTheme.colorScheme.primaryContainer
amount = "Flexible" amount = "Flexible"
} else if (card.amount == "") { }
card.amount == "" -> {
color = MaterialTheme.colorScheme.grayText color = MaterialTheme.colorScheme.grayText
amount = "Unknown" amount = "Unknown"
} else { }
else -> {
color = MaterialTheme.colorScheme.primary color = MaterialTheme.colorScheme.primary
amount = card.amount + " Sats" amount = card.amount + " Sats"
} }
}
Text( Text(
textAlign = TextAlign.End, textAlign = TextAlign.End,
text = " $amount ", text = " $amount ",
@@ -98,29 +98,35 @@ class NotificationSummaryState(
LocalCache.notes.forEach { _, it -> LocalCache.notes.forEach { _, it ->
val noteEvent = it.event val noteEvent = it.event
if (noteEvent != null && !takenIntoAccount.contains(noteEvent.id)) { if (noteEvent != null && !takenIntoAccount.contains(noteEvent.id)) {
if (noteEvent is ReactionEvent) { when {
noteEvent is ReactionEvent -> {
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) { if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) {
val netDate = formatDate(noteEvent.createdAt) val netDate = formatDate(noteEvent.createdAt)
reactions[netDate] = (reactions[netDate] ?: 0) + 1 reactions[netDate] = (reactions[netDate] ?: 0) + 1
takenIntoAccount.add(noteEvent.id) takenIntoAccount.add(noteEvent.id)
} }
} else if (noteEvent is RepostEvent || noteEvent is GenericRepostEvent) { }
noteEvent is RepostEvent || noteEvent is GenericRepostEvent -> {
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) { if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) {
val netDate = formatDate(noteEvent.createdAt) val netDate = formatDate(noteEvent.createdAt)
boosts[netDate] = (boosts[netDate] ?: 0) + 1 boosts[netDate] = (boosts[netDate] ?: 0) + 1
takenIntoAccount.add(noteEvent.id) takenIntoAccount.add(noteEvent.id)
} }
} else if (noteEvent is LnZapEvent) { }
noteEvent is LnZapEvent -> {
// the user might be sending his own receipts noteEvent.pubKey != currentUser // the user might be sending his own receipts noteEvent.pubKey != currentUser
if (noteEvent.isTaggedUser(currentUser)) { if (noteEvent.isTaggedUser(currentUser)) {
val netDate = formatDate(noteEvent.createdAt) val netDate = formatDate(noteEvent.createdAt)
zaps[netDate] = (zaps[netDate] ?: BigDecimal.ZERO) + (noteEvent.amount ?: BigDecimal.ZERO) zaps[netDate] = (zaps[netDate] ?: BigDecimal.ZERO) + (noteEvent.amount ?: BigDecimal.ZERO)
takenIntoAccount.add(noteEvent.id) takenIntoAccount.add(noteEvent.id)
} }
} else if (noteEvent is BaseThreadedEvent && }
noteEvent is BaseThreadedEvent &&
noteEvent.isTaggedUser(currentUser) && noteEvent.isTaggedUser(currentUser) &&
noteEvent.pubKey != currentUser noteEvent.pubKey != currentUser -> {
) {
val isCitation = val isCitation =
noteEvent.findCitations().any { noteEvent.findCitations().any {
LocalCache.getNoteIfExists(it)?.author?.pubkeyHex == currentUser LocalCache.getNoteIfExists(it)?.author?.pubkeyHex == currentUser
@@ -136,6 +142,7 @@ class NotificationSummaryState(
} }
} }
} }
}
this.takenIntoAccount = takenIntoAccount this.takenIntoAccount = takenIntoAccount
this.reactions.emit(reactions) this.reactions.emit(reactions)
@@ -162,21 +169,26 @@ class NotificationSummaryState(
newNotes.forEach { newNotes.forEach {
val noteEvent = it.event val noteEvent = it.event
if (noteEvent != null && !takenIntoAccount.contains(noteEvent.id)) { if (noteEvent != null && !takenIntoAccount.contains(noteEvent.id)) {
if (noteEvent is ReactionEvent) { when {
noteEvent is ReactionEvent -> {
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) { if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) {
val netDate = formatDate(noteEvent.createdAt) val netDate = formatDate(noteEvent.createdAt)
reactions[netDate] = (reactions[netDate] ?: 0) + 1 reactions[netDate] = (reactions[netDate] ?: 0) + 1
takenIntoAccount.add(noteEvent.id) takenIntoAccount.add(noteEvent.id)
hasNewElements = true hasNewElements = true
} }
} else if (noteEvent is RepostEvent || noteEvent is GenericRepostEvent) { }
noteEvent is RepostEvent || noteEvent is GenericRepostEvent -> {
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) { if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) {
val netDate = formatDate(noteEvent.createdAt) val netDate = formatDate(noteEvent.createdAt)
boosts[netDate] = (boosts[netDate] ?: 0) + 1 boosts[netDate] = (boosts[netDate] ?: 0) + 1
takenIntoAccount.add(noteEvent.id) takenIntoAccount.add(noteEvent.id)
hasNewElements = true hasNewElements = true
} }
} else if (noteEvent is LnZapEvent) { }
noteEvent is LnZapEvent -> {
if (noteEvent.isTaggedUser(currentUser)) { if (noteEvent.isTaggedUser(currentUser)) {
// && noteEvent.pubKey != currentUser User might be sending his own receipts // && noteEvent.pubKey != currentUser User might be sending his own receipts
val netDate = formatDate(noteEvent.createdAt) val netDate = formatDate(noteEvent.createdAt)
@@ -184,10 +196,11 @@ class NotificationSummaryState(
takenIntoAccount.add(noteEvent.id) takenIntoAccount.add(noteEvent.id)
hasNewElements = true hasNewElements = true
} }
} else if (noteEvent is BaseThreadedEvent && }
noteEvent is BaseThreadedEvent &&
noteEvent.isTaggedUser(currentUser) && noteEvent.isTaggedUser(currentUser) &&
noteEvent.pubKey != currentUser noteEvent.pubKey != currentUser -> {
) {
val isCitation = val isCitation =
noteEvent.findCitations().any { noteEvent.findCitations().any {
LocalCache.getNoteIfExists(it)?.author?.pubkeyHex == currentUser LocalCache.getNoteIfExists(it)?.author?.pubkeyHex == currentUser
@@ -205,6 +218,7 @@ class NotificationSummaryState(
} }
} }
} }
}
if (hasNewElements) { if (hasNewElements) {
this.takenIntoAccount = takenIntoAccount this.takenIntoAccount = takenIntoAccount
@@ -598,18 +598,26 @@ class NewPublicMessageViewModel :
fun autocompleteWithUser(item: User) { fun autocompleteWithUser(item: User) {
userSuggestions?.let { userSuggestions -> userSuggestions?.let { userSuggestions ->
if (userSuggestionsMainMessage == UserSuggestionAnchor.MAIN_MESSAGE) { when (userSuggestionsMainMessage) {
UserSuggestionAnchor.MAIN_MESSAGE -> {
val lastWord = message.currentWord() val lastWord = message.currentWord()
userSuggestions.replaceCurrentWord(message, lastWord, item) userSuggestions.replaceCurrentWord(message, lastWord, item)
urlPreviews.update(message.text.toString()) urlPreviews.update(message.text.toString())
} else if (userSuggestionsMainMessage == UserSuggestionAnchor.FORWARD_ZAPS) { }
UserSuggestionAnchor.FORWARD_ZAPS -> {
forwardZapTo.value.addItem(item) forwardZapTo.value.addItem(item)
forwardZapToEditting.value = TextFieldValue("") forwardZapToEditting.value = TextFieldValue("")
} else if (userSuggestionsMainMessage == UserSuggestionAnchor.TO_USERS) { }
UserSuggestionAnchor.TO_USERS -> {
val lastWord = toUsers.currentWord() val lastWord = toUsers.currentWord()
userSuggestions.replaceCurrentWord(toUsers, lastWord, item) userSuggestions.replaceCurrentWord(toUsers, lastWord, item)
} }
else -> {}
}
userSuggestionsMainMessage = null userSuggestionsMainMessage = null
userSuggestions.reset() userSuggestions.reset()
} }
@@ -79,7 +79,8 @@ fun GalleryThumbnail(
val noteEvent = noteState.note.event ?: return val noteEvent = noteState.note.event ?: return
val content = val content =
if (noteEvent is ProfileGalleryEntryEvent) { when {
noteEvent is ProfileGalleryEntryEvent -> {
noteEvent.urls().map { url -> noteEvent.urls().map { url ->
if (isVideoUrl(url)) { if (isVideoUrl(url)) {
MediaUrlVideo( MediaUrlVideo(
@@ -107,7 +108,9 @@ fun GalleryThumbnail(
) )
} }
} }
} else if (noteEvent is PictureEvent) { }
noteEvent is PictureEvent -> {
noteEvent.imetaTags().map { imeta -> noteEvent.imetaTags().map { imeta ->
MediaUrlImage( MediaUrlImage(
url = imeta.url, url = imeta.url,
@@ -121,7 +124,9 @@ fun GalleryThumbnail(
thumbhash = imeta.thumbhash, thumbhash = imeta.thumbhash,
) )
} }
} else if (noteEvent is VideoEvent) { }
noteEvent is VideoEvent -> {
// An HLS publish writes one imeta per rendition (master + each variant) on the same // An HLS publish writes one imeta per rendition (master + each variant) on the same
// NIP-71 event. Rendering them all expands a single video into a sub-grid of black // NIP-71 event. Rendering them all expands a single video into a sub-grid of black
// tiles inside one gallery card — the .m3u8 playlist is a text manifest Coil can't // tiles inside one gallery card — the .m3u8 playlist is a text manifest Coil can't
@@ -156,7 +161,9 @@ fun GalleryThumbnail(
artworkUri = imeta.image.firstOrNull(), artworkUri = imeta.image.firstOrNull(),
) )
} }
} else if (noteEvent is LiveActivitiesClipEvent) { }
noteEvent is LiveActivitiesClipEvent -> {
noteEvent.videoUrl()?.let { url -> noteEvent.videoUrl()?.let { url ->
listOf( listOf(
MediaUrlVideo( MediaUrlVideo(
@@ -171,9 +178,12 @@ fun GalleryThumbnail(
), ),
) )
} ?: emptyList() } ?: emptyList()
} else { }
else -> {
emptyList() emptyList()
} }
}
InnerRenderGalleryThumb(content, baseNote, accountViewModel) InnerRenderGalleryThumb(content, baseNote, accountViewModel)
} }
@@ -125,7 +125,8 @@ class SearchBarViewModel(
} else { } else {
null null
} }
if (nip05 != null) { when {
nip05 != null -> {
runCatching { runCatching {
nip05Client.get(nip05)?.let { info -> nip05Client.get(nip05)?.let { info ->
val user = account.cache.checkGetOrCreateUser(info.pubkey) val user = account.cache.checkGetOrCreateUser(info.pubkey)
@@ -139,7 +140,9 @@ class SearchBarViewModel(
user user
} }
}.getOrNull() }.getOrNull()
} else if (term.startsWithAny(userUriPrefixes)) { }
term.startsWithAny(userUriPrefixes) -> {
runCatching { runCatching {
Nip19Parser.uriToRoute(term)?.entity?.let { parsed -> Nip19Parser.uriToRoute(term)?.entity?.let { parsed ->
when (parsed) { when (parsed) {
@@ -165,11 +168,16 @@ class SearchBarViewModel(
} }
} }
}.getOrNull() }.getOrNull()
} else if (term.length == 64 && Hex.isHex64(term)) { }
term.length == 64 && Hex.isHex64(term) -> {
account.cache.getOrCreateUser(term) account.cache.getOrCreateUser(term)
} else { }
else -> {
null null
} }
}
}.flowOn(Dispatchers.IO) }.flowOn(Dispatchers.IO)
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
@@ -168,7 +168,8 @@ fun VideoFeedLoaded(
key = { _, item -> item.idHex }, key = { _, item -> item.idHex },
contentType = { _, item -> item.event?.kind ?: -1 }, contentType = { _, item -> item.event?.kind ?: -1 },
) { _, item -> ) { _, item ->
if (item.event is PictureEvent) { when {
item.event is PictureEvent -> {
PictureCardCompose( PictureCardCompose(
baseNote = item, baseNote = item,
accountViewModel = accountViewModel, accountViewModel = accountViewModel,
@@ -180,7 +181,9 @@ fun VideoFeedLoaded(
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
} else if (item.event is VideoEvent) { }
item.event is VideoEvent -> {
VideoCardCompose(item, accountViewModel, nav) VideoCardCompose(item, accountViewModel, nav)
HorizontalDivider( HorizontalDivider(
@@ -188,7 +191,9 @@ fun VideoFeedLoaded(
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
} else if (item.event is FileHeaderEvent) { }
item.event is FileHeaderEvent -> {
FileHeaderCardCompose(item, accountViewModel, nav) FileHeaderCardCompose(item, accountViewModel, nav)
HorizontalDivider( HorizontalDivider(
@@ -200,3 +205,4 @@ fun VideoFeedLoaded(
} }
} }
} }
}