mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-06 03:38:23 +00:00
Merge remote-tracking branch 'origin/main' into claude/happy-mccarthy-kdhg2s
# Conflicts: # amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/LoginScreen.kt # amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/signup/SignUpScreen.kt # amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt
This commit is contained in:
@@ -28,6 +28,8 @@ TASKS=(
|
||||
:quartz:jvmTest
|
||||
:commons:jvmTest
|
||||
:commonsUI:jvmTest
|
||||
# Android-only commonsUI code (e.g. SafeImeInsets) is tested here, not in jvmTest.
|
||||
:commonsUI:testAndroidHostTest
|
||||
:nestsClient:jvmTest
|
||||
:quic:jvmTest
|
||||
:marmotQuic:jvmTest
|
||||
|
||||
@@ -388,6 +388,7 @@ jobs:
|
||||
:quartz:jvmTest \
|
||||
:commons:jvmTest \
|
||||
:commonsUI:jvmTest \
|
||||
:commonsUI:testAndroidHostTest \
|
||||
:nestsClient:jvmTest \
|
||||
:amethyst:testFdroidDebugUnitTest \
|
||||
:amethyst:testPlayDebugUnitTest \
|
||||
|
||||
+2
-2
@@ -61,11 +61,11 @@ import org.junit.Test
|
||||
* [aCancelledImeAnimationMustNotWedgeTheAnimatedInset] FAILS on every version from 1.4.0 on, so it
|
||||
* is [Ignore]d to keep CI green. It is not a test of Amethyst code — it is the upstream repro we
|
||||
* attached to the bug. **Re-run it by hand after every Compose upgrade**: when it passes, the
|
||||
* upstream fix has landed and [com.vitorpamplona.amethyst.ui.insets.SafeImeInsets] can be retired.
|
||||
* upstream fix has landed and [com.vitorpamplona.amethyst.commons.ui.insets.SafeImeInsets] can be retired.
|
||||
*
|
||||
* [theAnimationTargetSurvivesTheWedge] documents the asymmetry that makes a workaround possible
|
||||
* and is expected to PASS — `updateImeAnimationTarget` is called outside the guard. It stays
|
||||
* enabled, because it guards the premise [com.vitorpamplona.amethyst.ui.insets.SafeImeInsets]
|
||||
* enabled, because it guards the premise [com.vitorpamplona.amethyst.commons.ui.insets.SafeImeInsets]
|
||||
* depends on: if a future Compose release stopped keeping `imeAnimationTarget` current, our
|
||||
* fallback would silently start reading a dead value too.
|
||||
*/
|
||||
|
||||
+1
-1
@@ -45,6 +45,7 @@ import androidx.media3.common.Player
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.ui.compose.ContentFrame
|
||||
import androidx.media3.ui.compose.SURFACE_TYPE_TEXTURE_VIEW
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.getDialogWindow
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.controls.BottomGradientOverlay
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.controls.FullscreenSwipeControlsState
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.controls.FullscreenSwipeLevelIndicator
|
||||
@@ -62,7 +63,6 @@ import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.LoadedMe
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.isHlsMedia
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.wavefront.AudioPlayingAnimation
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.wavefront.rememberIsAudioTrack
|
||||
import com.vitorpamplona.amethyst.ui.components.getDialogWindow
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
internal const val SKIP_SECONDS = 10
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.commons.actions.ConcordActions
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.richtext.RichTextParser
|
||||
import com.vitorpamplona.amethyst.debugState
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
|
||||
@@ -78,6 +78,7 @@ import com.vitorpamplona.amethyst.commons.resources.lightning_create_and_add_inv
|
||||
import com.vitorpamplona.amethyst.commons.resources.lightning_invoice
|
||||
import com.vitorpamplona.amethyst.commons.resources.what_s_on_your_mind
|
||||
import com.vitorpamplona.amethyst.commons.richtext.RichTextParser
|
||||
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.PostingTopBar
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.creators.invoice.AddLnInvoiceButton
|
||||
@@ -98,7 +99,6 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
|
||||
import com.vitorpamplona.amethyst.ui.components.BechLink
|
||||
import com.vitorpamplona.amethyst.ui.components.LoadUrlPreview
|
||||
import com.vitorpamplona.amethyst.ui.components.OutlinedThinPaddingTextField
|
||||
import com.vitorpamplona.amethyst.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.uploads.ImageVideoDescription
|
||||
|
||||
@@ -45,12 +45,12 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.copy_stack_to_clipboard
|
||||
import com.vitorpamplona.amethyst.commons.resources.error_dialog_button_ok
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size16dp
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer
|
||||
import com.vitorpamplona.amethyst.ui.components.toasts.ThrowableToastMsg
|
||||
import com.vitorpamplona.amethyst.ui.components.toasts.ThrowableToastMsg2
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
|
||||
@@ -73,6 +73,7 @@ import com.vitorpamplona.amethyst.commons.resources.video_codec_h265_description
|
||||
import com.vitorpamplona.amethyst.commons.resources.video_codec_h265_label
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.TextSpinner
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.TitleExplainer
|
||||
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.PostingTopBar
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.SettingSwitchItem
|
||||
@@ -82,7 +83,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.ShowImageUploadGallery
|
||||
import com.vitorpamplona.amethyst.ui.components.SetDialogToEdgeToEdge
|
||||
import com.vitorpamplona.amethyst.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsRow
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
+1
-1
@@ -75,12 +75,12 @@ import com.vitorpamplona.amethyst.commons.resources.twitter
|
||||
import com.vitorpamplona.amethyst.commons.resources.twitter_proof_url_template
|
||||
import com.vitorpamplona.amethyst.commons.resources.username
|
||||
import com.vitorpamplona.amethyst.commons.resources.website_url
|
||||
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.SavingTopBar
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectSingleFromGallery
|
||||
import com.vitorpamplona.amethyst.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
+1
-1
@@ -63,6 +63,7 @@ import com.vitorpamplona.amethyst.commons.resources.bolt12_offers_section_explai
|
||||
import com.vitorpamplona.amethyst.commons.resources.delete_bolt12_offer
|
||||
import com.vitorpamplona.amethyst.commons.resources.invalid_bolt12_offer
|
||||
import com.vitorpamplona.amethyst.commons.resources.no_bolt12_offers_message
|
||||
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.SavingTopBar
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
@@ -73,7 +74,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.grayText
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.abbreviateBolt12Offer
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategory
|
||||
|
||||
+1
-1
@@ -57,12 +57,12 @@ import com.vitorpamplona.amethyst.commons.resources.local_blossom_cache_profile_
|
||||
import com.vitorpamplona.amethyst.commons.resources.media_servers
|
||||
import com.vitorpamplona.amethyst.commons.resources.use_local_blossom_cache
|
||||
import com.vitorpamplona.amethyst.commons.resources.use_local_blossom_cache_caption
|
||||
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.TopBarWithBackButton
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.grayText
|
||||
import com.vitorpamplona.amethyst.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@Composable
|
||||
|
||||
+1
-1
@@ -128,6 +128,7 @@ import com.vitorpamplona.amethyst.commons.resources.manage_stored_files_empty
|
||||
import com.vitorpamplona.amethyst.commons.resources.my_blossom_data
|
||||
import com.vitorpamplona.amethyst.commons.resources.quick_action_share
|
||||
import com.vitorpamplona.amethyst.commons.resources.retry
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
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
|
||||
@@ -135,7 +136,6 @@ import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.grayText
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.VideoViewInner
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
|
||||
+1
-1
@@ -69,6 +69,7 @@ import com.vitorpamplona.amethyst.commons.resources.nests_servers_relay_label
|
||||
import com.vitorpamplona.amethyst.commons.resources.nests_servers_remove
|
||||
import com.vitorpamplona.amethyst.commons.resources.nests_servers_title
|
||||
import com.vitorpamplona.amethyst.commons.resources.nests_servers_use_defaults
|
||||
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.SavingTopBar
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
@@ -82,7 +83,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.grayText
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.ui.actions.mediaServers.AllMediaServersScreen
|
||||
import com.vitorpamplona.amethyst.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategory
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategoryWithButton
|
||||
|
||||
+1
-1
@@ -61,6 +61,7 @@ import com.vitorpamplona.amethyst.commons.resources.payment_target_type
|
||||
import com.vitorpamplona.amethyst.commons.resources.payment_targets
|
||||
import com.vitorpamplona.amethyst.commons.resources.payment_targets_explainer
|
||||
import com.vitorpamplona.amethyst.commons.resources.payment_targets_section_explainer
|
||||
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.SavingTopBar
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
@@ -71,7 +72,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.grayText
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategory
|
||||
import com.vitorpamplona.quartz.experimental.nipA3.PaymentTarget
|
||||
|
||||
@@ -57,6 +57,7 @@ import com.vitorpamplona.amethyst.commons.resources.cashu_mint_label
|
||||
import com.vitorpamplona.amethyst.commons.resources.cashu_no_wallet_found
|
||||
import com.vitorpamplona.amethyst.commons.resources.cashu_redeem
|
||||
import com.vitorpamplona.amethyst.commons.resources.sats
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.OpenInNewIcon
|
||||
@@ -68,7 +69,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn
|
||||
import com.vitorpamplona.amethyst.service.cashu.CachedCashuParser
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.nip60Cashu.token.CashuToken
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
@@ -93,7 +93,7 @@ fun CashuPreview(
|
||||
}
|
||||
}
|
||||
|
||||
CrossfadeIfEnabled(targetState = cashuData, label = "CashuPreview", accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = cashuData, label = "CashuPreview") {
|
||||
when (it) {
|
||||
is GenericLoadable.Loaded<ImmutableList<CashuToken>> -> {
|
||||
CashuPreview(it.loaded, accountViewModel)
|
||||
|
||||
+1
-1
@@ -30,8 +30,8 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalClipboard
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import com.vitorpamplona.quartz.buzz.invite.BuzzInviteLink
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
+1
-1
@@ -31,8 +31,8 @@ import androidx.compose.ui.platform.LocalClipboard
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.vitorpamplona.amethyst.commons.actions.ConcordActions
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -30,8 +30,8 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalClipboard
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import com.vitorpamplona.quartz.nip29RelayGroups.GroupInviteLink
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
+1
-1
@@ -30,8 +30,8 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalClipboard
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -20,12 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.text.InlineTextContent
|
||||
import androidx.compose.foundation.text.appendInlineContent
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -34,34 +28,29 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.takeOrElse
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.text.LinkAnnotation
|
||||
import androidx.compose.ui.text.Placeholder
|
||||
import androidx.compose.ui.text.PlaceholderVerticalAlign
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.TextLinkStyles
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.text.withLink
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil3.compose.AsyncImage
|
||||
import com.vitorpamplona.amethyst.commons.model.EmptyTagList
|
||||
import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.concord_invite_naddr_label
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.richtext.ClickableInLineIconRenderer
|
||||
import com.vitorpamplona.amethyst.commons.ui.richtext.CreateClickableTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.commons.ui.richtext.CustomEmojiChecker
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.util.njumpLink
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote
|
||||
@@ -84,9 +73,6 @@ import com.vitorpamplona.quartz.nip19Bech32.entities.NSec
|
||||
import com.vitorpamplona.quartz.nip19Bech32.toNIP19
|
||||
import com.vitorpamplona.quartz.nip29RelayGroups.GroupNAddrInvite
|
||||
import com.vitorpamplona.quartz.nip29RelayGroups.metadata.GroupMetadataEvent
|
||||
import com.vitorpamplona.quartz.nip30CustomEmoji.CustomEmoji
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
|
||||
@Composable
|
||||
fun ClickableRoute(
|
||||
@@ -406,208 +392,6 @@ fun CreateClickableText(
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CustomEmojiChecker(
|
||||
text: String,
|
||||
tags: ImmutableListOfLists<String>?,
|
||||
onRegularText: @Composable (String) -> Unit,
|
||||
onEmojiText: @Composable (ImmutableList<CustomEmoji.Renderable>) -> Unit,
|
||||
) {
|
||||
val mayContainEmoji by remember(text, tags) {
|
||||
mutableStateOf(CustomEmoji.fastMightContainEmoji(text, tags?.lists))
|
||||
}
|
||||
|
||||
if (mayContainEmoji) {
|
||||
var emojiList by
|
||||
remember(text, tags) {
|
||||
mutableStateOf<ImmutableList<CustomEmoji.Renderable>?>(null)
|
||||
}
|
||||
|
||||
LaunchedEffect(text, tags) {
|
||||
val newEmojiList = CustomEmoji.assembleAnnotatedList(text, tags?.lists)
|
||||
if (newEmojiList != null) {
|
||||
emojiList = newEmojiList
|
||||
}
|
||||
}
|
||||
|
||||
emojiList?.let {
|
||||
onEmojiText(it)
|
||||
} ?: run {
|
||||
onRegularText(text)
|
||||
}
|
||||
} else {
|
||||
onRegularText(text)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CustomEmojiChecker(
|
||||
text: String,
|
||||
emojis: ImmutableMap<String, String>,
|
||||
onRegularText: @Composable (String) -> Unit,
|
||||
onEmojiText: @Composable (ImmutableList<CustomEmoji.Renderable>) -> Unit,
|
||||
) {
|
||||
val mayContainEmoji by remember(text, emojis) {
|
||||
mutableStateOf(CustomEmoji.fastMightContainEmoji(text, emojis))
|
||||
}
|
||||
|
||||
if (mayContainEmoji) {
|
||||
var emojiList by
|
||||
remember(text, emojis) {
|
||||
mutableStateOf<ImmutableList<CustomEmoji.Renderable>?>(null)
|
||||
}
|
||||
|
||||
LaunchedEffect(text, emojis) {
|
||||
val newEmojiList = CustomEmoji.assembleAnnotatedList(text, emojis)
|
||||
if (newEmojiList != null) {
|
||||
emojiList = newEmojiList
|
||||
}
|
||||
}
|
||||
|
||||
emojiList?.let {
|
||||
onEmojiText(it)
|
||||
} ?: run {
|
||||
onRegularText(text)
|
||||
}
|
||||
} else {
|
||||
onRegularText(text)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CreateTextWithEmoji(
|
||||
text: String,
|
||||
tags: ImmutableListOfLists<String>?,
|
||||
color: Color = Color.Unspecified,
|
||||
textAlign: TextAlign? = null,
|
||||
fontWeight: FontWeight? = null,
|
||||
fontSize: TextUnit = TextUnit.Unspecified,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
overflow: TextOverflow = TextOverflow.Clip,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
CustomEmojiChecker(
|
||||
text,
|
||||
tags,
|
||||
onEmojiText = {
|
||||
val textColor =
|
||||
color.takeOrElse { LocalTextStyle.current.color.takeOrElse { LocalContentColor.current } }
|
||||
val style =
|
||||
LocalTextStyle.current
|
||||
.merge(
|
||||
TextStyle(
|
||||
color = textColor,
|
||||
textAlign = TextAlign.Unspecified,
|
||||
fontWeight = fontWeight,
|
||||
fontSize = fontSize,
|
||||
),
|
||||
).toSpanStyle()
|
||||
|
||||
InLineIconRenderer(it, style, fontSize, maxLines, overflow, modifier)
|
||||
},
|
||||
onRegularText = {
|
||||
val textColor =
|
||||
color.takeOrElse { LocalTextStyle.current.color.takeOrElse { LocalContentColor.current } }
|
||||
Text(
|
||||
text = it,
|
||||
color = textColor,
|
||||
textAlign = textAlign,
|
||||
fontWeight = fontWeight,
|
||||
fontSize = fontSize,
|
||||
maxLines = maxLines,
|
||||
overflow = overflow,
|
||||
modifier = modifier,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CreateTextWithEmoji(
|
||||
text: String,
|
||||
emojis: ImmutableMap<String, String>,
|
||||
color: Color = Color.Unspecified,
|
||||
textAlign: TextAlign? = null,
|
||||
fontWeight: FontWeight? = null,
|
||||
fontSize: TextUnit = TextUnit.Unspecified,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
overflow: TextOverflow = TextOverflow.Clip,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val textColor =
|
||||
color.takeOrElse { LocalTextStyle.current.color.takeOrElse { LocalContentColor.current } }
|
||||
|
||||
CustomEmojiChecker(
|
||||
text,
|
||||
emojis,
|
||||
onEmojiText = {
|
||||
val currentStyle = LocalTextStyle.current
|
||||
val style =
|
||||
remember(currentStyle) {
|
||||
currentStyle
|
||||
.merge(
|
||||
TextStyle(
|
||||
color = textColor,
|
||||
textAlign = TextAlign.Unspecified,
|
||||
fontWeight = fontWeight,
|
||||
fontSize = fontSize,
|
||||
),
|
||||
).toSpanStyle()
|
||||
}
|
||||
|
||||
InLineIconRenderer(it, style, fontSize, maxLines, overflow, modifier)
|
||||
},
|
||||
onRegularText = {
|
||||
Text(
|
||||
text = it,
|
||||
color = textColor,
|
||||
textAlign = textAlign,
|
||||
fontWeight = fontWeight,
|
||||
fontSize = fontSize,
|
||||
maxLines = maxLines,
|
||||
overflow = overflow,
|
||||
modifier = modifier,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CreateClickableTextWithEmoji(
|
||||
clickablePart: String,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
tags: ImmutableListOfLists<String>?,
|
||||
style: TextStyle,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
CustomEmojiChecker(
|
||||
text = clickablePart,
|
||||
tags = tags,
|
||||
onRegularText = {
|
||||
Text(
|
||||
text =
|
||||
buildAnnotatedString {
|
||||
withLink(
|
||||
LinkAnnotation.Clickable(
|
||||
"me",
|
||||
TextLinkStyles(style = style.toSpanStyle()),
|
||||
) {
|
||||
onClick()
|
||||
},
|
||||
) {
|
||||
append(clickablePart)
|
||||
}
|
||||
},
|
||||
style = style,
|
||||
maxLines = maxLines,
|
||||
)
|
||||
},
|
||||
onEmojiText = {
|
||||
ClickableInLineIconRenderer(it, maxLines, style.toSpanStyle(), onClick = onClick)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CreateClickableTextWithEmoji(
|
||||
clickablePart: String,
|
||||
@@ -653,144 +437,3 @@ fun CreateClickableTextWithEmoji(
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ClickableInLineIconRenderer(
|
||||
wordsInOrder: ImmutableList<CustomEmoji.Renderable>,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
style: SpanStyle,
|
||||
suffix: String? = null,
|
||||
nonClickableStype: SpanStyle? = null,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
val placeholderSize =
|
||||
remember(style) {
|
||||
if (style.fontSize == TextUnit.Unspecified) 22.sp else style.fontSize.times(1.1f)
|
||||
}
|
||||
|
||||
val inlineContent =
|
||||
wordsInOrder
|
||||
.mapIndexedNotNull { idx, value ->
|
||||
if (value is CustomEmoji.ImageUrlType) {
|
||||
Pair(
|
||||
"inlineContent$idx",
|
||||
InlineTextContent(
|
||||
Placeholder(
|
||||
width = placeholderSize,
|
||||
height = placeholderSize,
|
||||
placeholderVerticalAlign = PlaceholderVerticalAlign.Center,
|
||||
),
|
||||
) {
|
||||
AsyncImage(
|
||||
model = value.url,
|
||||
contentDescription = null,
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.padding(1.dp),
|
||||
)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}.associate { it.first to it.second }
|
||||
|
||||
val annotatedText =
|
||||
buildAnnotatedString {
|
||||
wordsInOrder.forEachIndexed { idx, value ->
|
||||
withLink(
|
||||
LinkAnnotation.Clickable("link", TextLinkStyles(style)) {
|
||||
onClick()
|
||||
},
|
||||
) {
|
||||
if (value is CustomEmoji.TextType) {
|
||||
append(value.text)
|
||||
} else if (value is CustomEmoji.ImageUrlType) {
|
||||
appendInlineContent("inlineContent$idx", "[icon]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (suffix != null && nonClickableStype != null) {
|
||||
withStyle(nonClickableStype) {
|
||||
append(suffix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
text = annotatedText,
|
||||
inlineContent = inlineContent,
|
||||
maxLines = maxLines,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun InLineIconRenderer(
|
||||
wordsInOrder: ImmutableList<CustomEmoji.Renderable>,
|
||||
style: SpanStyle,
|
||||
fontSize: TextUnit = TextUnit.Unspecified,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
overflow: TextOverflow = TextOverflow.Clip,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val placeholderSize =
|
||||
remember(fontSize) {
|
||||
if (fontSize == TextUnit.Unspecified) 22.sp else fontSize.times(1.1f)
|
||||
}
|
||||
|
||||
val inlineContent =
|
||||
wordsInOrder
|
||||
.mapIndexedNotNull { idx, value ->
|
||||
if (value is CustomEmoji.ImageUrlType) {
|
||||
Pair(
|
||||
"inlineContent$idx",
|
||||
InlineTextContent(
|
||||
Placeholder(
|
||||
width = placeholderSize,
|
||||
height = placeholderSize,
|
||||
placeholderVerticalAlign = PlaceholderVerticalAlign.Center,
|
||||
),
|
||||
) {
|
||||
AsyncImage(
|
||||
model = value.url,
|
||||
contentDescription = null,
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.padding(horizontal = 0.dp),
|
||||
)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}.associate { it.first to it.second }
|
||||
|
||||
val annotatedText =
|
||||
remember {
|
||||
buildAnnotatedString {
|
||||
wordsInOrder.forEachIndexed { idx, value ->
|
||||
withStyle(
|
||||
style,
|
||||
) {
|
||||
if (value is CustomEmoji.TextType) {
|
||||
append(value.text)
|
||||
} else if (value is CustomEmoji.ImageUrlType) {
|
||||
appendInlineContent("inlineContent$idx", "[icon]")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
text = annotatedText,
|
||||
inlineContent = inlineContent,
|
||||
fontSize = fontSize,
|
||||
maxLines = maxLines,
|
||||
overflow = overflow,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
+2
-2
@@ -34,8 +34,8 @@ import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.error_dialog_pay_withdraw_error
|
||||
import com.vitorpamplona.amethyst.commons.resources.no_wallet_found
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.note.ErrorMessageDialog
|
||||
import com.vitorpamplona.amethyst.ui.note.payViaIntent
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
@@ -54,7 +54,7 @@ fun MayBeWithdrawal(
|
||||
launch(Dispatchers.IO) { lnWithdrawal = LnWithdrawalUtil.findWithdrawal(lnurlWord) }
|
||||
}
|
||||
|
||||
CrossfadeIfEnabled(targetState = lnWithdrawal, accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = lnWithdrawal) {
|
||||
if (it != null) {
|
||||
ClickableWithdrawal(withdrawalString = it)
|
||||
} else {
|
||||
|
||||
@@ -29,11 +29,11 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlPdf
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewState
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HalfVertPadding
|
||||
import com.vitorpamplona.amethyst.model.UrlCachedPreviewer
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@Composable
|
||||
@@ -82,7 +82,6 @@ fun LoadUrlPreviewDirect(
|
||||
CrossfadeIfEnabled(
|
||||
targetState = urlPreviewState,
|
||||
label = "UrlPreview",
|
||||
accountViewModel = accountViewModel,
|
||||
) { state ->
|
||||
when (state) {
|
||||
is UrlPreviewState.Loaded -> {
|
||||
|
||||
@@ -38,13 +38,13 @@ import coil3.compose.AsyncImagePainter
|
||||
import coil3.compose.SubcomposeAsyncImage
|
||||
import coil3.compose.SubcomposeAsyncImageContent
|
||||
import com.vitorpamplona.amethyst.commons.richtext.isAnimatedMediaUrl
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.DownloadForOfflineIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size40dp
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size6dp
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size75dp
|
||||
import com.vitorpamplona.amethyst.model.MediaAspectRatioCache
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@Composable
|
||||
@@ -74,7 +74,7 @@ fun MyAsyncImage(
|
||||
val ratio = MediaAspectRatioCache.get(imageUrl)
|
||||
val showImage = remember { mutableStateOf(accountViewModel.settings.showImages()) }
|
||||
|
||||
CrossfadeIfEnabled(targetState = showImage.value, contentAlignment = Alignment.Center, accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = showImage.value, contentAlignment = Alignment.Center) {
|
||||
if (it) {
|
||||
SubcomposeAsyncImage(
|
||||
model = imageUrl,
|
||||
|
||||
@@ -50,10 +50,10 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.copied_to_clipboard
|
||||
import com.vitorpamplona.amethyst.commons.resources.copy_to_clipboard
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.QuoteBorder
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size18Modifier
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
|
||||
+1
-3
@@ -56,6 +56,7 @@ import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_
|
||||
import com.vitorpamplona.amethyst.commons.resources.no_wallet_found
|
||||
import com.vitorpamplona.amethyst.commons.resources.no_zap_amount_setup_long_press_to_change
|
||||
import com.vitorpamplona.amethyst.commons.resources.thank_you
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.ZapIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.ZappedIcon
|
||||
@@ -66,7 +67,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp
|
||||
import com.vitorpamplona.amethyst.service.ZapPaymentHandler
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.UserFinderFilterAssemblerSubscription
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.components.toasts.multiline.UserBasedErrorMessage
|
||||
import com.vitorpamplona.amethyst.ui.note.ObserveZapIcon
|
||||
import com.vitorpamplona.amethyst.ui.note.ZapAmountChoicePopup
|
||||
@@ -254,7 +254,6 @@ fun ReusableZapButton(
|
||||
CrossfadeIfEnabled(
|
||||
targetState = wasZappedByLoggedInUser.value,
|
||||
label = "ZapIcon",
|
||||
accountViewModel = accountViewModel,
|
||||
) {
|
||||
if (it) {
|
||||
ZappedIcon(config.iconSizeModifier)
|
||||
@@ -286,7 +285,6 @@ fun ReusableZapButton(
|
||||
CrossfadeIfEnabled(
|
||||
targetState = wasZappedByLoggedInUser.value,
|
||||
label = "ZapIcon",
|
||||
accountViewModel = accountViewModel,
|
||||
) {
|
||||
if (it) {
|
||||
ZappedIcon(config.iconSizeModifier)
|
||||
|
||||
@@ -70,6 +70,7 @@ import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.richtext.Base64Segment
|
||||
import com.vitorpamplona.amethyst.commons.richtext.BechSegment
|
||||
import com.vitorpamplona.amethyst.commons.richtext.BlossomUriSegment
|
||||
@@ -102,9 +103,12 @@ import com.vitorpamplona.amethyst.commons.richtext.VideoSegment
|
||||
import com.vitorpamplona.amethyst.commons.richtext.WithdrawSegment
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.AnimatedBorderTextCornerRadius
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.NowhereLinkCard
|
||||
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.CreateClickableTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.commons.ui.richtext.HashtagIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.richtext.checkForHashtagWithIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.state.produceCachedState
|
||||
@@ -116,7 +120,6 @@ import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.UserFinder
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserNickname
|
||||
import com.vitorpamplona.amethyst.service.uploads.blossom.bud10.openBlossomUriAsIntent
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.invoice.ClinkOfferPreview
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.invoice.MayBeInvoicePreview
|
||||
@@ -977,7 +980,7 @@ private fun DisplayUserFromTag(
|
||||
val nickname by observeUserNickname(baseUser, accountViewModel)
|
||||
val petName = nickname?.petName
|
||||
|
||||
CrossfadeIfEnabled(targetState = meta, label = "DisplayUserFromTag", accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = meta, label = "DisplayUserFromTag") {
|
||||
Row {
|
||||
CreateClickableTextWithEmoji(
|
||||
clickablePart = remember(meta, petName) { petName ?: it?.info?.bestName() ?: baseUser.pubkeyDisplayHex() },
|
||||
|
||||
+3
-3
@@ -67,12 +67,12 @@ import com.vitorpamplona.amethyst.commons.resources.content_warning_explanation
|
||||
import com.vitorpamplona.amethyst.commons.resources.content_warning_with_reason
|
||||
import com.vitorpamplona.amethyst.commons.resources.show_anyway
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ButtonPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.PaddingHorizontal12Modifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip36SensitiveContent.ContentWarningTag
|
||||
@@ -154,7 +154,7 @@ fun ContentWarningGate(
|
||||
}
|
||||
}
|
||||
|
||||
CrossfadeIfEnabled(targetState = showContentWarningNote, accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = showContentWarningNote) {
|
||||
if (it) {
|
||||
if (backdrop != null) {
|
||||
Box(modifier = modifier.clipToBounds()) {
|
||||
@@ -180,7 +180,7 @@ fun ObserveSensitivityWarning(
|
||||
|
||||
var showContentWarningNote by remember(accountState) { mutableStateOf(accountState.value != true) }
|
||||
|
||||
CrossfadeIfEnabled(targetState = showContentWarningNote, accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = showContentWarningNote) {
|
||||
if (it) {
|
||||
ContentWarningNote(reason) { showContentWarningNote = false }
|
||||
} else {
|
||||
|
||||
+1
@@ -29,6 +29,7 @@ import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.window.DialogWindowProvider
|
||||
import androidx.core.view.WindowCompat
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.getActivityWindow
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.isLight
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -51,13 +51,13 @@ import com.vitorpamplona.amethyst.commons.resources.url_preview_open_in_browser
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.M3ActionDialog
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.M3ActionRow
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.M3ActionSection
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.MaxWidthWithHorzPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size14Modifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.innerPostModifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.previewCardImageModifier
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
|
||||
@@ -20,31 +20,13 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.components
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.view.Window
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.window.DialogWindowProvider
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
|
||||
// Window utils
|
||||
@Composable
|
||||
fun getDialogWindow(): Window? = (LocalView.current.parent as? DialogWindowProvider)?.window
|
||||
|
||||
@Composable
|
||||
fun getActivityWindow(): Window? = LocalView.current.context.getActivityWindow()
|
||||
|
||||
private tailrec fun Context.getActivityWindow(): Window? =
|
||||
when (this) {
|
||||
is Activity -> window
|
||||
is ContextWrapper -> baseContext.getActivityWindow()
|
||||
else -> null
|
||||
}
|
||||
|
||||
tailrec fun Context.getActivity(): ComponentActivity =
|
||||
when (this) {
|
||||
is ComponentActivity -> this
|
||||
|
||||
+2
@@ -80,6 +80,8 @@ import com.vitorpamplona.amethyst.commons.richtext.MediaUrlContent
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlPdf
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.getActivityWindow
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.getDialogWindow
|
||||
import com.vitorpamplona.amethyst.commons.ui.loadStringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier
|
||||
import com.vitorpamplona.amethyst.model.MediaAspectRatioCache
|
||||
|
||||
+4
-4
@@ -106,10 +106,12 @@ import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo
|
||||
import com.vitorpamplona.amethyst.commons.richtext.RichTextParser
|
||||
import com.vitorpamplona.amethyst.commons.richtext.isAnimatedMediaUrl
|
||||
import com.vitorpamplona.amethyst.commons.service.image.placeholderModel
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.M3ActionDialog
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.M3ActionRow
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.M3ActionSection
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.loadStringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.DownloadForOfflineIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
@@ -125,11 +127,9 @@ import com.vitorpamplona.amethyst.model.MediaAspectRatioCache
|
||||
import com.vitorpamplona.amethyst.service.images.BlossomFetcher
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.VideoView
|
||||
import com.vitorpamplona.amethyst.service.uploads.blossom.bud10.openBlossomUriAsIntent
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.actions.InformationDialog
|
||||
import com.vitorpamplona.amethyst.ui.components.pdf.PdfPreviewCard
|
||||
import com.vitorpamplona.amethyst.ui.components.pdf.PdfViewerDialog
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.ui.note.BlankNote
|
||||
import com.vitorpamplona.amethyst.ui.painterRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
@@ -414,7 +414,7 @@ fun LocalImageView(
|
||||
} else {
|
||||
content.localFile
|
||||
}
|
||||
CrossfadeIfEnabled(targetState = showImage.value, contentAlignment = Alignment.Center, accountViewModel = accountViewModel) { imageVisible ->
|
||||
CrossfadeIfEnabled(targetState = showImage.value, contentAlignment = Alignment.Center) { imageVisible ->
|
||||
if (imageVisible) {
|
||||
SubcomposeAsyncImage(
|
||||
model = imageModel,
|
||||
@@ -547,7 +547,7 @@ fun UrlImageView(
|
||||
content.url
|
||||
}
|
||||
|
||||
CrossfadeIfEnabled(targetState = showImage.value, contentAlignment = Alignment.Center, accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = showImage.value, contentAlignment = Alignment.Center) {
|
||||
if (it) {
|
||||
SubcomposeAsyncImage(
|
||||
model = imageModel,
|
||||
|
||||
+1
-1
@@ -62,6 +62,7 @@ import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.core.graphics.createBitmap
|
||||
import coil3.disk.DiskCache
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlPdf
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.getDialogWindow
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp
|
||||
import com.vitorpamplona.amethyst.ui.components.ImmersiveSystemBarsEffect
|
||||
@@ -69,7 +70,6 @@ import com.vitorpamplona.amethyst.ui.components.ViewerBackButton
|
||||
import com.vitorpamplona.amethyst.ui.components.ViewerControlsRow
|
||||
import com.vitorpamplona.amethyst.ui.components.ViewerSaveToGalleryButton
|
||||
import com.vitorpamplona.amethyst.ui.components.ViewerShareButton
|
||||
import com.vitorpamplona.amethyst.ui.components.getDialogWindow
|
||||
import com.vitorpamplona.amethyst.ui.components.rememberViewerControlsVisibility
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
|
||||
+1
@@ -36,6 +36,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.copied_to_clipboard
|
||||
import com.vitorpamplona.amethyst.commons.resources.copy_to_clipboard
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.loadStringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -30,6 +30,7 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedEmpty
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedError
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed
|
||||
@@ -37,7 +38,6 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverLazyGridState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverLazyListState
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@Composable
|
||||
@@ -111,7 +111,6 @@ fun RenderFeedContentState(
|
||||
CrossfadeIfEnabled(
|
||||
targetState = feedState,
|
||||
animationSpec = tween(durationMillis = 100),
|
||||
accountViewModel = accountViewModel,
|
||||
) { state ->
|
||||
when (state) {
|
||||
is FeedState.Empty -> onEmpty()
|
||||
|
||||
+17
-337
@@ -20,57 +20,17 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.layouts
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.layout.SubcomposeLayout
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.unit.Constraints
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingBarNestedScroll
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingBarState
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.LocalDisappearingBarState
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.LocalDisappearingScaffoldPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.rememberDisappearingBarState
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.ui.components.getActivityWindow
|
||||
import com.vitorpamplona.amethyst.ui.insets.SafeImeInsets
|
||||
import com.vitorpamplona.amethyst.ui.insets.rememberSafeImeInsets
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.LocalScreenLayout
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
private enum class DisappearingSlot { Top, Bottom, Content, Fab }
|
||||
|
||||
private val FabEdgePadding = 16.dp
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold as SharedDisappearingScaffold
|
||||
|
||||
/**
|
||||
* The app's [SharedDisappearingScaffold]: bars hide on scroll only when the user's immersive
|
||||
* scrolling setting is on, and never on large screens (rail / permanent drawer), which pin the
|
||||
* chrome.
|
||||
*/
|
||||
@Composable
|
||||
fun DisappearingScaffold(
|
||||
isInvertedLayout: Boolean,
|
||||
@@ -81,293 +41,13 @@ fun DisappearingScaffold(
|
||||
isActive: () -> Boolean = { true },
|
||||
allowBarHide: Boolean = true,
|
||||
mainContent: @Composable (padding: PaddingValues) -> Unit,
|
||||
) {
|
||||
val state = rememberDisappearingBarState()
|
||||
|
||||
// Large screens (rail / permanent drawer) pin the chrome: bars never slide away on
|
||||
// scroll, and the immersive status-bar hiding stays off.
|
||||
val canHideBars = allowBarHide && !LocalScreenLayout.current.isLargeScreen
|
||||
|
||||
// Hold the latest values in state so the NSC's captured lambda stays fresh across
|
||||
// recompositions without rebuilding the NSC itself.
|
||||
val latestIsActive by rememberUpdatedState(isActive)
|
||||
val latestAllowBarHide by rememberUpdatedState(canHideBars)
|
||||
val latestAccountViewModel by rememberUpdatedState(accountViewModel)
|
||||
|
||||
val connection =
|
||||
remember(state, isInvertedLayout) {
|
||||
DisappearingBarNestedScroll(
|
||||
state = state,
|
||||
canScroll = {
|
||||
latestAllowBarHide &&
|
||||
latestIsActive() &&
|
||||
latestAccountViewModel.settings.isImmersiveScrollingActive()
|
||||
},
|
||||
reverseLayout = isInvertedLayout,
|
||||
)
|
||||
}
|
||||
|
||||
// Only wire the lifecycle observer + system-bar control when the scaffold actually moves its bars.
|
||||
if (canHideBars) {
|
||||
ResetBarsOnResume(state)
|
||||
ImmersiveStatusBarEffect(state)
|
||||
}
|
||||
|
||||
// If the bars were scrolled away when hiding got disabled (e.g. the window grew to a
|
||||
// large tier mid-scroll), nothing above can bring them back — the nested-scroll
|
||||
// connection and the resume reset are gone. Snap them visible here instead of
|
||||
// leaving the chrome stranded off-screen.
|
||||
LaunchedEffect(canHideBars, state) {
|
||||
if (!canHideBars) state.resetToVisible()
|
||||
}
|
||||
|
||||
// When bars are pinned, skip attaching the nested-scroll connection entirely.
|
||||
// The outer Surface provides the Material container color + onBackground as
|
||||
// LocalContentColor, matching M3 Scaffold's behaviour (without it, default text
|
||||
// color falls back to Color.Black and is invisible on the dark theme).
|
||||
// Hoisted above the branch: imePaddingSafe() inside both arms would put the call in two
|
||||
// different composition groups, so toggling canHideBars (a window-size-class change) would
|
||||
// dispose and rebuild it. Resolved once here, and handed to ScaffoldLayout below so the value
|
||||
// this pads with is the same object the nav-bar subtraction reads.
|
||||
val imeInsets = rememberSafeImeInsets()
|
||||
val baseModifier =
|
||||
if (canHideBars) {
|
||||
Modifier.windowInsetsPadding(imeInsets).nestedScroll(connection)
|
||||
} else {
|
||||
Modifier.windowInsetsPadding(imeInsets)
|
||||
}
|
||||
val rootModifier =
|
||||
baseModifier
|
||||
// systemBars (not just statusBars) so a desktop window's caption bar is respected too.
|
||||
.let { if (topBar == null) it.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Top)) else it }
|
||||
.let { if (bottomBar == null) it.navigationBarsPadding() else it }
|
||||
|
||||
Surface(
|
||||
modifier = rootModifier,
|
||||
color = MaterialTheme.colorScheme.background,
|
||||
contentColor = MaterialTheme.colorScheme.onBackground,
|
||||
) {
|
||||
ScaffoldLayout(
|
||||
state = state,
|
||||
topBar = topBar,
|
||||
bottomBar = bottomBar,
|
||||
floatingButton = floatingButton,
|
||||
imeInsets = imeInsets,
|
||||
mainContent = mainContent,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ScaffoldLayout(
|
||||
state: DisappearingBarState,
|
||||
topBar: (@Composable () -> Unit)?,
|
||||
bottomBar: (@Composable () -> Unit)?,
|
||||
floatingButton: (@Composable () -> Unit)?,
|
||||
imeInsets: SafeImeInsets,
|
||||
mainContent: @Composable (padding: PaddingValues) -> Unit,
|
||||
) {
|
||||
val navBarInsets = WindowInsets.navigationBars
|
||||
SubcomposeLayout { constraints ->
|
||||
val layoutWidth = constraints.maxWidth
|
||||
val layoutHeight = constraints.maxHeight
|
||||
val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0)
|
||||
|
||||
val topPlaceable =
|
||||
topBar?.let { bar ->
|
||||
subcompose(DisappearingSlot.Top) {
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.graphicsLayer {
|
||||
translationY = state.topHeightOffset
|
||||
},
|
||||
) {
|
||||
bar()
|
||||
HorizontalDivider(thickness = DividerThickness)
|
||||
}
|
||||
}.firstOrNull()?.measure(looseConstraints)
|
||||
}
|
||||
val topHeight = topPlaceable?.height ?: 0
|
||||
|
||||
val bottomPlaceable =
|
||||
bottomBar?.let { bar ->
|
||||
subcompose(DisappearingSlot.Bottom) {
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.graphicsLayer {
|
||||
translationY = -state.bottomHeightOffset
|
||||
},
|
||||
) {
|
||||
bar()
|
||||
}
|
||||
}.firstOrNull()?.measure(looseConstraints)
|
||||
}
|
||||
// When the bar lambda is provided but its content emits nothing (e.g. AppBottomBar
|
||||
// hides itself on canPop entries, or while the keyboard is up), reserve the
|
||||
// system-nav-bar inset so the FAB and content stay clear of the navigation bar instead
|
||||
// of sliding under it. Subtract the IME inset: the root imePadding has already lifted the
|
||||
// whole scaffold above the keyboard, and the IME inset spans the nav-bar band, so
|
||||
// reserving the full nav bar on top of that would double-count and strand a gap above the
|
||||
// keyboard (the `bottomBar == null` branch gets this for free via navigationBarsPadding,
|
||||
// which excludes the consumed IME inset). The `bottomBar == null` case is on rootModifier.
|
||||
val bottomHeight =
|
||||
(bottomPlaceable?.height ?: 0).let { measured ->
|
||||
if (bottomBar != null && measured == 0) {
|
||||
(navBarInsets.getBottom(this) - imeInsets.getBottom(this)).coerceAtLeast(0)
|
||||
} else {
|
||||
measured
|
||||
}
|
||||
}
|
||||
|
||||
// Publish the measured limits so the nested-scroll connection can clamp correctly.
|
||||
state.topHeightLimit = topHeight.toFloat()
|
||||
state.bottomHeightLimit = bottomHeight.toFloat()
|
||||
|
||||
val contentPadding =
|
||||
PaddingValues(
|
||||
top = topHeight.toDp(),
|
||||
bottom = bottomHeight.toDp(),
|
||||
)
|
||||
|
||||
val contentPlaceable =
|
||||
subcompose(DisappearingSlot.Content) {
|
||||
CompositionLocalProvider(
|
||||
LocalDisappearingScaffoldPadding provides contentPadding,
|
||||
LocalDisappearingBarState provides state,
|
||||
) {
|
||||
mainContent(contentPadding)
|
||||
}
|
||||
}.firstOrNull()?.measure(
|
||||
Constraints.fixed(layoutWidth, layoutHeight),
|
||||
)
|
||||
|
||||
val fabPlaceable =
|
||||
floatingButton?.let { fab ->
|
||||
subcompose(DisappearingSlot.Fab) {
|
||||
FloatingButtonHolder(state = state) { fab() }
|
||||
}.firstOrNull()?.measure(looseConstraints)
|
||||
}
|
||||
|
||||
val fabEdgePx = FabEdgePadding.roundToPx()
|
||||
|
||||
layout(layoutWidth, layoutHeight) {
|
||||
contentPlaceable?.place(0, 0)
|
||||
topPlaceable?.place(0, 0)
|
||||
bottomPlaceable?.place(0, layoutHeight - bottomHeight)
|
||||
if (fabPlaceable != null) {
|
||||
val x = layoutWidth - fabPlaceable.width - fabEdgePx
|
||||
val yBase = layoutHeight - bottomHeight - fabPlaceable.height - fabEdgePx
|
||||
fabPlaceable.place(x, yBase)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds the floating button. Scales / fades it with the bottom-bar collapse fraction and
|
||||
* rides along with the bar via graphicsLayer, so the layout pass is untouched while
|
||||
* the bar animates.
|
||||
*/
|
||||
@Composable
|
||||
private fun FloatingButtonHolder(
|
||||
state: DisappearingBarState,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
Box(
|
||||
modifier =
|
||||
Modifier.graphicsLayer {
|
||||
val visible = (1f - state.bottomCollapsedFraction).coerceAtLeast(0.001f)
|
||||
scaleX = visible
|
||||
scaleY = visible
|
||||
alpha = visible
|
||||
translationY = -state.bottomHeightOffset
|
||||
},
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ResetBarsOnResume(state: DisappearingBarState) {
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val scope = rememberCoroutineScope()
|
||||
DisposableEffect(lifecycleOwner, state) {
|
||||
val observer =
|
||||
LifecycleEventObserver { _, event ->
|
||||
if (event == Lifecycle.Event.ON_RESUME &&
|
||||
(state.topHeightOffset != 0f || state.bottomHeightOffset != 0f)
|
||||
) {
|
||||
scope.launch { state.resetToVisible() }
|
||||
}
|
||||
}
|
||||
lifecycleOwner.lifecycle.addObserver(observer)
|
||||
onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
|
||||
}
|
||||
}
|
||||
|
||||
/** Fraction at which the tracked in-app bar is considered fully settled into the hidden edge. */
|
||||
private const val STATUS_BAR_HIDE_THRESHOLD = 0.999f
|
||||
|
||||
/**
|
||||
* Fraction the chrome must fall back below before the OS status bar reappears. Lower than
|
||||
* [STATUS_BAR_HIDE_THRESHOLD] on purpose: this hysteresis gap means the finger that stops a fast
|
||||
* scroll — which makes a tiny reverse reveal — does not immediately pop the status bar back. The
|
||||
* user has to deliberately scroll the chrome back by ~30% before the status bar returns.
|
||||
*/
|
||||
private const val STATUS_BAR_SHOW_THRESHOLD = 0.7f
|
||||
|
||||
/**
|
||||
* Hides the OS status bar once the tracked in-app bar has settled into the hidden edge, and shows it
|
||||
* the moment it starts coming back. The OS status bar is binary (cannot slide), so it is driven off
|
||||
* the collapse fraction with a near-1 threshold, which means it toggles on settle rather than
|
||||
* mid-drag.
|
||||
*
|
||||
* The status bar sits with the top in-app bar, so it tracks the top bar's collapse. The top and
|
||||
* bottom bars can collapse at different rates (each clamps to its own height), so tracking the top
|
||||
* fraction keeps the status bar in step with the chrome directly beneath it. On screens with no top
|
||||
* bar (topHeightLimit == 0) it falls back to the bottom bar, so the status bar still hides in sync
|
||||
* with the bottom navigation.
|
||||
*
|
||||
* Only the top status bar is touched; the bottom OS navigation bar is left alone.
|
||||
* BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE lets the user swipe to peek the status bar while immersed.
|
||||
* The status bar is always restored on dispose so leaving an immersive screen can never strand a
|
||||
* hidden bar.
|
||||
*/
|
||||
@Composable
|
||||
private fun ImmersiveStatusBarEffect(state: DisappearingBarState) {
|
||||
val view = LocalView.current
|
||||
if (view.isInEditMode) return
|
||||
val window = getActivityWindow() ?: return
|
||||
val controller = remember(window, view) { WindowInsetsControllerCompat(window, view) }
|
||||
|
||||
LaunchedEffect(controller, state) {
|
||||
controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||
var statusBarHidden = false
|
||||
snapshotFlow {
|
||||
if (state.topHeightLimit > 0f) state.topCollapsedFraction else state.bottomCollapsedFraction
|
||||
}.distinctUntilChanged()
|
||||
.collect { fraction ->
|
||||
// Hysteresis: hide once fully settled, but only show again after the chrome has
|
||||
// been pulled back past STATUS_BAR_SHOW_THRESHOLD. Between the two thresholds the
|
||||
// status bar keeps its current state, so a stray reverse reveal can't flip it.
|
||||
val shouldHide =
|
||||
when {
|
||||
fraction >= STATUS_BAR_HIDE_THRESHOLD -> true
|
||||
fraction <= STATUS_BAR_SHOW_THRESHOLD -> false
|
||||
else -> statusBarHidden
|
||||
}
|
||||
if (shouldHide != statusBarHidden) {
|
||||
statusBarHidden = shouldHide
|
||||
if (shouldHide) {
|
||||
controller.hide(WindowInsetsCompat.Type.statusBars())
|
||||
} else {
|
||||
controller.show(WindowInsetsCompat.Type.statusBars())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DisposableEffect(controller) {
|
||||
onDispose { controller.show(WindowInsetsCompat.Type.statusBars()) }
|
||||
}
|
||||
}
|
||||
) = SharedDisappearingScaffold(
|
||||
isInvertedLayout = isInvertedLayout,
|
||||
topBar = topBar,
|
||||
bottomBar = bottomBar,
|
||||
floatingButton = floatingButton,
|
||||
immersiveScrolling = { accountViewModel.settings.isImmersiveScrollingActive() },
|
||||
isActive = isActive,
|
||||
allowBarHide = allowBarHide && !LocalScreenLayout.current.isLargeScreen,
|
||||
mainContent = mainContent,
|
||||
)
|
||||
|
||||
@@ -29,52 +29,14 @@ import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSiz
|
||||
import androidx.compose.material3.windowsizeclass.WindowSizeClass
|
||||
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/** How the app shell presents its top-level navigation for the current window size. */
|
||||
enum class NavigationStyle {
|
||||
/** Compact windows (phones): bottom navigation bar + modal drawer. */
|
||||
BOTTOM_BAR,
|
||||
|
||||
/**
|
||||
* Every non-Compact window that does not dock — portrait tablets and unfolded foldables at
|
||||
* any width, plus short landscape windows: a left navigation rail replaces the bottom bar
|
||||
* and the drawer stays modal behind the rail's avatar button.
|
||||
*/
|
||||
NAV_RAIL,
|
||||
|
||||
/** Wide, landscape, tall windows (landscape tablets, desktop): the drawer docks permanently on the left. */
|
||||
PERMANENT_DRAWER,
|
||||
}
|
||||
|
||||
/**
|
||||
* The shell layout decisions for the current window, published once per window size change
|
||||
* through [LocalScreenLayout] so every screen, bar and panel agrees on the same tier.
|
||||
*/
|
||||
@Immutable
|
||||
data class ScreenLayoutSpec(
|
||||
val navigationStyle: NavigationStyle,
|
||||
val hasRoomForNotificationPanel: Boolean,
|
||||
) {
|
||||
/**
|
||||
* True on the rail and permanent-drawer tiers. Large screens hide the bottom bar and pin
|
||||
* the top/bottom chrome (no disappearing bars on scroll).
|
||||
*/
|
||||
val isLargeScreen: Boolean get() = navigationStyle != NavigationStyle.BOTTOM_BAR
|
||||
|
||||
companion object {
|
||||
val Phone = ScreenLayoutSpec(NavigationStyle.BOTTOM_BAR, hasRoomForNotificationPanel = false)
|
||||
}
|
||||
}
|
||||
|
||||
val LocalScreenLayout = compositionLocalOf { ScreenLayoutSpec.Phone }
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.NavigationStyle
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.ScreenLayoutSpec
|
||||
|
||||
/**
|
||||
* Minimum window width for the docked notification panel: a leading navigation pane, a
|
||||
|
||||
@@ -58,6 +58,7 @@ import com.vitorpamplona.amethyst.commons.relayClient.user.LocalUserFinderAccoun
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.invalid_nip19_uri
|
||||
import com.vitorpamplona.amethyst.commons.resources.invalid_nip19_uri_description
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.LocalScreenLayout
|
||||
import com.vitorpamplona.amethyst.service.crashreports.DisplayCrashMessages
|
||||
import com.vitorpamplona.amethyst.service.relayClient.authCommand.compose.RelayAuthPromptHost
|
||||
import com.vitorpamplona.amethyst.service.relayClient.notifyCommand.compose.DisplayNotifyMessages
|
||||
@@ -74,7 +75,6 @@ import com.vitorpamplona.amethyst.ui.broadcast.DisplayBroadcastProgress
|
||||
import com.vitorpamplona.amethyst.ui.call.CallActivity
|
||||
import com.vitorpamplona.amethyst.ui.components.getActivity
|
||||
import com.vitorpamplona.amethyst.ui.components.toasts.DisplayErrorMessages
|
||||
import com.vitorpamplona.amethyst.ui.layouts.LocalScreenLayout
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberScreenLayoutSpec
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.LocalTabReselectCoordinator
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.TabReselectCoordinator
|
||||
|
||||
+1
-1
@@ -49,6 +49,7 @@ import com.vitorpamplona.amethyst.commons.favorites.FavoriteAppIcon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.BottomBarEntry
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.LocalScreenLayout
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness
|
||||
@@ -61,7 +62,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.onSurface65
|
||||
import com.vitorpamplona.amethyst.favorites.BrowserIconRegistry
|
||||
import com.vitorpamplona.amethyst.favorites.FavoriteAppsRegistry
|
||||
import com.vitorpamplona.amethyst.favorites.rememberNappletIconModel
|
||||
import com.vitorpamplona.amethyst.ui.layouts.LocalScreenLayout
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
/** Content height of the [AppBottomBar] (the 50.dp Column inside [RenderBottomMenu]),
|
||||
|
||||
+3
-4
@@ -25,8 +25,7 @@ import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import com.vitorpamplona.amethyst.ui.insets.SafeImeInsets
|
||||
import com.vitorpamplona.amethyst.ui.insets.rememberSafeImeInsets
|
||||
import com.vitorpamplona.amethyst.commons.ui.insets.rememberSafeImeInsets
|
||||
|
||||
enum class KeyboardState {
|
||||
Opened,
|
||||
@@ -36,7 +35,7 @@ enum class KeyboardState {
|
||||
/**
|
||||
* Whether the soft keyboard is currently on screen, derived from the IME inset.
|
||||
*
|
||||
* This intentionally reads the same [SafeImeInsets] that drives `Modifier.imePaddingSafe()`
|
||||
* This intentionally reads the same [SafeImeInsets][com.vitorpamplona.amethyst.commons.ui.insets.SafeImeInsets] that drives `Modifier.imePaddingSafe()`
|
||||
* everywhere else in the app, so the two can never disagree about whether the keyboard is up.
|
||||
*
|
||||
* The original implementation measured `View.getWindowVisibleDisplayFrame` from a
|
||||
@@ -48,7 +47,7 @@ enum class KeyboardState {
|
||||
*
|
||||
* Reading `WindowInsets.ime` fixed that, but has a latch of its own: Compose stops updating the
|
||||
* inset entirely once its insets listener is left mid-animation, which pins this back at [Opened]
|
||||
* in exactly the same way. [SafeImeInsets] is what closes that last hole, which is why this reads
|
||||
* in exactly the same way. [SafeImeInsets][com.vitorpamplona.amethyst.commons.ui.insets.SafeImeInsets] is what closes that last hole, which is why this reads
|
||||
* the corrected inset rather than the raw one.
|
||||
*/
|
||||
@Composable
|
||||
|
||||
+1
-1
@@ -74,12 +74,12 @@ import com.vitorpamplona.amethyst.commons.scheduledposts.ScheduledPostStatus
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
|
||||
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.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.AccountPictureModifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo
|
||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.ui.note.toShortDisplay
|
||||
import com.vitorpamplona.amethyst.ui.screen.AccountSessionManager
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
+2
-1
@@ -98,6 +98,7 @@ import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.DrawerSectionId
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.NavBarItem
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.bookmarks
|
||||
import com.vitorpamplona.amethyst.commons.resources.drafts
|
||||
@@ -120,6 +121,7 @@ import com.vitorpamplona.amethyst.commons.scheduledposts.ScheduledPostStatus
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
|
||||
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.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer
|
||||
@@ -147,7 +149,6 @@ import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNo
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserContactCardsFollowerCount
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserStatuses
|
||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.ui.layouts.PermanentDrawerWidth
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.NavBarCatalog
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.NavBarItemDef
|
||||
|
||||
@@ -26,9 +26,8 @@ import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import com.vitorpamplona.amethyst.commons.ui.insets.rememberSafeImeInsets
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav
|
||||
import com.vitorpamplona.amethyst.ui.insets.SafeImeInsets
|
||||
import com.vitorpamplona.amethyst.ui.insets.rememberSafeImeInsets
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
|
||||
@@ -44,7 +43,7 @@ const val IME_SETTLE_TIMEOUT_MS = 700L
|
||||
* [WindowInsetsAnimationCompat][androidx.core.view.WindowInsetsAnimationCompat] is cancelled before
|
||||
* its terminal (zero) frame reaches Compose. `WindowInsets.ime` is a single app-wide holder, so it
|
||||
* stays "animating" and every IME padding in the app — not just the screen being left — freezes at
|
||||
* the keyboard height. [SafeImeInsets] is the backstop for when that freeze turns out to be
|
||||
* the keyboard height. [SafeImeInsets][com.vitorpamplona.amethyst.commons.ui.insets.SafeImeInsets] is the backstop for when that freeze turns out to be
|
||||
* permanent; this is the prevention, and it is the cheaper of the two because it keeps the padding
|
||||
* from ever being wrong.
|
||||
*
|
||||
@@ -64,7 +63,7 @@ fun interface ImeSettler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the same [SafeImeInsets] that drives `Modifier.imePaddingSafe()`, so the settler and the
|
||||
* Reads the same [SafeImeInsets][com.vitorpamplona.amethyst.commons.ui.insets.SafeImeInsets] that drives `Modifier.imePaddingSafe()`, so the settler and the
|
||||
* padding can never disagree about whether the keyboard is gone. Reading the raw `WindowInsets.ime`
|
||||
* here would make every navigation burn the full [IME_SETTLE_TIMEOUT_MS] once the inset is stranded,
|
||||
* waiting on a value that is never going to move again.
|
||||
|
||||
+2
-51
@@ -24,17 +24,16 @@ import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.model.concord.ConcordChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.marmotGroups.MarmotGroupChatroom
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.minichatRouteFor
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.buzz.notifications.MemberAddedNotificationEvent
|
||||
import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent
|
||||
import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId
|
||||
import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.application.SoftwareApplicationEvent
|
||||
import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent
|
||||
@@ -79,34 +78,6 @@ import com.vitorpamplona.quartz.nipA4PublicMessages.PublicMessageEvent
|
||||
import com.vitorpamplona.quartz.nipCCGeocaching.curation.GeocacheCurationListEvent
|
||||
import com.vitorpamplona.quartz.nipCCGeocaching.listing.GeocacheListingEvent
|
||||
|
||||
/**
|
||||
* A minichat reply — a kind-1111 [CommentEvent] posted into a chat message's thread — should open
|
||||
* that message's minichat ([Route.ChatMinichat]), not the whole channel it lives in. Regular chat
|
||||
* messages are kind 9 / 42, so a [CommentEvent] in a *chat context* is always a thread reply. We
|
||||
* gate on the chat context (the reply is attached to a Concord / relay-group / public-chat gatherer,
|
||||
* or its root message is) precisely so a generic NIP-22 comment on an article or note keeps its own
|
||||
* thread route and isn't mistaken for a minichat. Returns null when it isn't a chat-context comment.
|
||||
*/
|
||||
fun minichatRouteFor(note: Note): Route? {
|
||||
val comment = note.event as? CommentEvent ?: return null
|
||||
val rootId = comment.rootEventIds().firstOrNull() ?: return null
|
||||
|
||||
// Prefer the reply's own Concord channel (the reply arrived over that plane, so its gatherer
|
||||
// always carries the community/channel), else the root note's if it happens to be loaded. Passing
|
||||
// these lets the minichat screen resolve the plane + relays even when the parent isn't cached.
|
||||
val concord =
|
||||
note.inGatherers?.firstNotNullOfOrNull { it as? ConcordChannel }
|
||||
?: LocalCache.getNoteIfExists(rootId)?.inGatherers?.firstNotNullOfOrNull { it as? ConcordChannel }
|
||||
if (concord != null) {
|
||||
return Route.ChatMinichat(rootId, concord.channelId.communityId, concord.channelId.channelId)
|
||||
}
|
||||
|
||||
val inChatContext = note.isInChatGatherer() || LocalCache.getNoteIfExists(rootId)?.isInChatGatherer() == true
|
||||
return if (inChatContext) Route.ChatMinichat(rootId) else null
|
||||
}
|
||||
|
||||
private fun Note.isInChatGatherer(): Boolean = inGatherers?.any { it is ConcordChannel || it is RelayGroupChannel || it is PublicChatChannel } == true
|
||||
|
||||
/**
|
||||
* Kinds whose destination is `Route.Note(id)` — the generic thread view — no matter what the
|
||||
* event body turns out to say. Mirrors the `else ->` branch of [routeForInner]: every kind here
|
||||
@@ -419,26 +390,6 @@ fun routeToMessage(
|
||||
accountViewModel: AccountViewModel,
|
||||
): Route = routeToMessage(user.pubkeyHex, draftMessage, replyId, draftId, expiresDays, accountViewModel)
|
||||
|
||||
fun routeFor(note: EphemeralChatChannel): Route = Route.EphemeralChat(note.roomId.id, note.roomId.relayUrl.url)
|
||||
|
||||
fun routeFor(note: PublicChatChannel): Route = Route.PublicChatChannel(note.idHex)
|
||||
|
||||
fun routeFor(note: LiveActivitiesChannel): Route = Route.LiveActivityChannel(note.address.kind, note.address.pubKeyHex, note.address.dTag)
|
||||
|
||||
fun routeFor(roomId: RoomId): Route = Route.EphemeralChat(roomId.id, roomId.relayUrl.url)
|
||||
|
||||
fun routeFor(note: RelayGroupChannel): Route = Route.RelayGroup(note.groupId.id, note.groupId.relayUrl.url)
|
||||
|
||||
fun routeFor(groupId: GroupId): Route = Route.RelayGroup(groupId.id, groupId.relayUrl.url)
|
||||
|
||||
fun routeFor(channel: ConcordChannel): Route = Route.Concord(channel.channelId.communityId, channel.channelId.channelId)
|
||||
|
||||
fun routeFor(user: User): Route.Profile = Route.Profile(user.pubkeyHex)
|
||||
|
||||
fun routeForUser(userHex: HexKey): Route.Profile = Route.Profile(userHex)
|
||||
|
||||
fun authorRouteFor(note: Note): Route.Profile? = note.author?.pubkeyHex?.let { Route.Profile(it) }
|
||||
|
||||
fun routeReplyTo(
|
||||
note: Note,
|
||||
account: Account,
|
||||
|
||||
+1
-1
@@ -37,6 +37,7 @@ import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.your_profile_image
|
||||
import com.vitorpamplona.amethyst.commons.search.SearchQuery
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.LocalScreenLayout
|
||||
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
|
||||
@@ -46,7 +47,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HeaderPictureModifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size22Modifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserPicture
|
||||
import com.vitorpamplona.amethyst.ui.layouts.LocalScreenLayout
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,6 +40,7 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.new_badge_award_notif
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
|
||||
@@ -36,6 +36,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import com.vitorpamplona.amethyst.commons.model.Bolt12ZapEntry
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.ZappedIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp
|
||||
|
||||
@@ -35,9 +35,9 @@ import com.vitorpamplona.amethyst.commons.resources.copy_text_translated
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.M3ActionDialog
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.M3ActionRow
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.M3ActionSection
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.components.cachedTranslation
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.ui.note.types.displayedNoteText
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -24,9 +24,9 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.SimpleImageBorder
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.BannerImage
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@@ -45,7 +45,7 @@ fun DisplayAuthorBanner(
|
||||
)
|
||||
} else {
|
||||
val authorState by observeNote(baseNote, accountViewModel)
|
||||
CrossfadeIfEnabled(authorState.note.author, accountViewModel = accountViewModel) { author ->
|
||||
CrossfadeIfEnabled(authorState.note.author) { author ->
|
||||
if (author != null) {
|
||||
BannerImage(
|
||||
author,
|
||||
|
||||
@@ -36,10 +36,11 @@ import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeForUser
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeForUser
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@@ -40,6 +40,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdStartPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
|
||||
@@ -72,6 +72,8 @@ import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.NoteState
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.authorRouteFor
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.nutzap
|
||||
import com.vitorpamplona.amethyst.commons.resources.profile_image
|
||||
@@ -84,6 +86,7 @@ import com.vitorpamplona.amethyst.commons.ui.note.LikedIcon
|
||||
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.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HalfTopPadding
|
||||
@@ -106,9 +109,7 @@ import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUse
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserPicture
|
||||
import com.vitorpamplona.amethyst.ui.components.CoreSecretMessage
|
||||
import com.vitorpamplona.amethyst.ui.components.ExpandableRichTextViewer
|
||||
import com.vitorpamplona.amethyst.ui.components.InLineIconRenderer
|
||||
import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.authorRouteFor
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
+5
-4
@@ -49,6 +49,8 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.AddressableNote
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeForUser
|
||||
import com.vitorpamplona.amethyst.commons.model.nip05DnsIdentifiers.Nip05State
|
||||
import com.vitorpamplona.amethyst.commons.model.nip05DnsIdentifiers.Nip05VerifState
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
@@ -56,7 +58,9 @@ import com.vitorpamplona.amethyst.commons.resources.nip05_checking
|
||||
import com.vitorpamplona.amethyst.commons.resources.nip05_failed
|
||||
import com.vitorpamplona.amethyst.commons.resources.nip05_verified
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Font14SP
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.NIP05IconSize
|
||||
@@ -69,11 +73,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserStatuses
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.ui.components.LoadNote
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeForUser
|
||||
import com.vitorpamplona.amethyst.ui.painterRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser
|
||||
@@ -466,7 +467,7 @@ fun RenderNIP05VerifiedSymbol(
|
||||
modifier: Modifier,
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
CrossfadeIfEnabled(targetState = state, accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = state) {
|
||||
when (it) {
|
||||
is Nip05VerifState.Verifying, is Nip05VerifState.NotStarted -> {
|
||||
// Treat "not started" and "in flight" as a single loading visual so the
|
||||
|
||||
@@ -66,6 +66,7 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.model.concord.ConcordChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.isCommunityDefinition
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.replyingDirectlyTo
|
||||
|
||||
@@ -100,6 +100,7 @@ import com.vitorpamplona.amethyst.commons.resources.quick_action_unfollow
|
||||
import com.vitorpamplona.amethyst.commons.resources.quick_action_unmute_thread
|
||||
import com.vitorpamplona.amethyst.commons.resources.report_dialog_block_hide_user_btn
|
||||
import com.vitorpamplona.amethyst.commons.resources.report_dialog_blocking_a_user
|
||||
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.stringRes
|
||||
@@ -109,7 +110,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.SmallestBorder
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.isLight
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.secondaryButtonBackground
|
||||
import com.vitorpamplona.amethyst.commons.util.njumpLink
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeEditDraftTo
|
||||
import com.vitorpamplona.amethyst.ui.painterRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.vitorpamplona.amethyst.commons.hashtags.Cashu
|
||||
import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.NutzapEntry
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.nutzap
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
|
||||
@@ -37,6 +37,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.hashtags.Cashu
|
||||
import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.nutzap
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
|
||||
@@ -41,6 +41,7 @@ import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.OnchainZapEntry
|
||||
import com.vitorpamplona.amethyst.commons.model.OnchainZapStatus
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.OnchainZappedIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.PendingClockBadge
|
||||
|
||||
@@ -152,7 +152,9 @@ import com.vitorpamplona.amethyst.commons.resources.reload_mint_title
|
||||
import com.vitorpamplona.amethyst.commons.resources.sats_to_complete
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.AnimatedBorderTextCornerRadius
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.ClickableBox
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.ChangeReactionIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.CommentIcon
|
||||
@@ -167,6 +169,7 @@ import com.vitorpamplona.amethyst.commons.ui.note.ShareIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.VoiceReplyIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.ZapIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.ZappedIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.richtext.InLineIconRenderer
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder
|
||||
@@ -222,13 +225,10 @@ import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNo
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteZaps
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.nwc.NWCFinderFilterAssemblerSubscription
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.FloatingRecordingIndicator
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.MAX_VOICE_RECORD_SECONDS
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.RecordAudioBox
|
||||
import com.vitorpamplona.amethyst.ui.components.InLineIconRenderer
|
||||
import com.vitorpamplona.amethyst.ui.components.toasts.multiline.UserBasedErrorMessage
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeReplyTo
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.ShareOptionsBottomSheet
|
||||
import com.vitorpamplona.amethyst.ui.note.types.EditState
|
||||
@@ -603,7 +603,6 @@ private fun RenderShowIndividualReactionsButton(
|
||||
CrossfadeIfEnabled(
|
||||
targetState = wantsToSeeReactions.value,
|
||||
label = "RenderShowIndividualReactionsButton",
|
||||
accountViewModel = accountViewModel,
|
||||
) {
|
||||
if (it) {
|
||||
ExpandLessIcon(modifier = Size22Modifier, Res.string.close_all_reactions_to_this_post)
|
||||
@@ -1112,7 +1111,7 @@ fun LikeReaction(
|
||||
onLongClick = { nav.nav(Route.UpdateReactionType) },
|
||||
) {
|
||||
ObserveLikeIcon(baseNote, accountViewModel) { reactionType ->
|
||||
CrossfadeIfEnabled(targetState = reactionType, contentAlignment = Center, label = "LikeIcon", accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = reactionType, contentAlignment = Center, label = "LikeIcon") {
|
||||
if (reactionType != null) {
|
||||
RenderReactionType(reactionType, heartSizeModifier, iconFontSize)
|
||||
} else {
|
||||
@@ -1447,7 +1446,7 @@ fun ZapReaction(
|
||||
accountViewModel,
|
||||
zapStartingTime,
|
||||
) { zapIconState ->
|
||||
CrossfadeIfEnabled(targetState = zapIconState, label = "ZapIcon", accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = zapIconState, label = "ZapIcon") {
|
||||
if (it.wasZappedByLoggedInUser) {
|
||||
ZappedIcon(iconSizeModifier)
|
||||
} else {
|
||||
@@ -1460,7 +1459,7 @@ fun ZapReaction(
|
||||
baseNote,
|
||||
accountViewModel,
|
||||
) { zapIconState ->
|
||||
CrossfadeIfEnabled(targetState = zapIconState, label = "ZapIcon", accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = zapIconState, label = "ZapIcon") {
|
||||
if (it.wasZappedByLoggedInUser) {
|
||||
ZappedIcon(iconSizeModifier)
|
||||
} else if (it.hasPendingPaymentRequest) {
|
||||
|
||||
@@ -50,13 +50,13 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.expand_relay_list
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ShowMoreRelaysButtonBoxModifer
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size17Modifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
@@ -130,7 +130,7 @@ private fun RenderRelaySlot(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
CrossfadeIfEnabled(targetState = relay, label = "RenderRelay", modifier = Size17Modifier, accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = relay, label = "RenderRelay", modifier = Size17Modifier) {
|
||||
if (it != null) {
|
||||
RenderRelay(it, accountViewModel, nav)
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ import com.vitorpamplona.amethyst.commons.resources.expand_relay_list
|
||||
import com.vitorpamplona.amethyst.commons.resources.relay_info
|
||||
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.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.LargeRelayIconModifier
|
||||
@@ -71,7 +72,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.relayIconModifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ripple24dp
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.warningColorOnSecondSurface
|
||||
import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -35,10 +35,12 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.and
|
||||
import com.vitorpamplona.amethyst.commons.resources.replying_to
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.richtext.CreateClickableTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.lessImportantLink
|
||||
|
||||
+3
-2
@@ -72,13 +72,16 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.commons.emojicoder.EmojiCoder
|
||||
import com.vitorpamplona.amethyst.commons.model.AddressableNote
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.add
|
||||
import com.vitorpamplona.amethyst.commons.resources.new_reaction_symbol
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.AnimatedBorderTextCornerRadius
|
||||
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.SavingTopBar
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.LikedIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.richtext.InLineIconRenderer
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
@@ -86,8 +89,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.commons.util.firstFullChar
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEventAndMapNotNull
|
||||
import com.vitorpamplona.amethyst.ui.components.InLineIconRenderer
|
||||
import com.vitorpamplona.amethyst.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderEmojiPack
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@@ -110,6 +110,7 @@ import com.vitorpamplona.amethyst.commons.resources.zap_type_public_explainer
|
||||
import com.vitorpamplona.amethyst.commons.resources.zap_type_section_explainer
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.TextSpinner
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.TitleExplainer
|
||||
import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.SettingsCategoryFirstModifier
|
||||
@@ -117,7 +118,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.SettingsCategorySpacingModifi
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.keyBackup.getFragmentActivity
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel
|
||||
|
||||
@@ -34,6 +34,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.profile.ui.FollowButton
|
||||
import com.vitorpamplona.amethyst.commons.profile.ui.ListButton
|
||||
import com.vitorpamplona.amethyst.commons.profile.ui.UnfollowButton
|
||||
|
||||
@@ -39,6 +39,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.profile_image
|
||||
import com.vitorpamplona.amethyst.commons.resources.profile_image_of_user
|
||||
|
||||
@@ -23,30 +23,26 @@ package com.vitorpamplona.amethyst.ui.note
|
||||
import android.content.Context
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.PlayIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.UserNameText
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdButtonSizeModifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserNickname
|
||||
import com.vitorpamplona.amethyst.service.tts.TextToSpeechHelper
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
|
||||
@@ -91,7 +87,7 @@ fun WatchAuthorWithBlank(
|
||||
inner(noteAuthor)
|
||||
} else {
|
||||
val authorState by observeNote(baseNote, accountViewModel)
|
||||
CrossfadeIfEnabled(targetState = authorState.note.author, modifier = modifier, label = "WatchAuthorWithBlank", accountViewModel = accountViewModel) { newAuthor ->
|
||||
CrossfadeIfEnabled(targetState = authorState.note.author, modifier = modifier, label = "WatchAuthorWithBlank") { newAuthor ->
|
||||
inner(newAuthor)
|
||||
}
|
||||
}
|
||||
@@ -109,59 +105,22 @@ fun UsernameDisplay(
|
||||
val userMetadata by observeUserInfo(baseUser, accountViewModel)
|
||||
val nickname by observeUserNickname(baseUser, accountViewModel)
|
||||
|
||||
CrossfadeIfEnabled(targetState = userMetadata, modifier = weight, label = "UsernameDisplay", accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = userMetadata, modifier = weight, label = "UsernameDisplay") {
|
||||
// the account's own nickname for this user wins over the user's metadata;
|
||||
// its custom emojis resolve against the contact card's tags, not the profile's
|
||||
val petName = nickname?.petName
|
||||
val name = petName ?: it?.info?.bestName()
|
||||
if (name != null) {
|
||||
UserDisplay(name, if (petName != null) nickname?.tags else it?.tags, weight, fontWeight, textColor, textAlign)
|
||||
} else {
|
||||
NPubDisplay(baseUser, weight, fontWeight, textColor, textAlign)
|
||||
}
|
||||
UserNameText(
|
||||
user = baseUser,
|
||||
displayName = petName ?: it?.info?.bestName(),
|
||||
tags = if (petName != null) nickname?.tags else it?.tags,
|
||||
modifier = weight,
|
||||
fontWeight = fontWeight,
|
||||
textColor = textColor,
|
||||
textAlign = textAlign,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NPubDisplay(
|
||||
user: User,
|
||||
modifier: Modifier,
|
||||
fontWeight: FontWeight = FontWeight.Bold,
|
||||
textColor: Color = Color.Unspecified,
|
||||
textAlign: TextAlign? = null,
|
||||
) {
|
||||
Text(
|
||||
text = remember { user.pubkeyDisplayHex() },
|
||||
fontWeight = fontWeight,
|
||||
modifier = modifier,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = textColor,
|
||||
textAlign = textAlign,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UserDisplay(
|
||||
bestDisplayName: String,
|
||||
tags: ImmutableListOfLists<String>?,
|
||||
modifier: Modifier,
|
||||
fontWeight: FontWeight = FontWeight.Bold,
|
||||
textColor: Color = Color.Unspecified,
|
||||
textAlign: TextAlign? = null,
|
||||
) {
|
||||
CreateTextWithEmoji(
|
||||
text = bestDisplayName,
|
||||
tags = tags,
|
||||
fontWeight = fontWeight,
|
||||
textAlign = textAlign,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = modifier,
|
||||
color = textColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DrawPlayName(name: String) {
|
||||
val context = LocalContext.current
|
||||
|
||||
@@ -27,10 +27,10 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteHasEvent
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.UserFinderByParentFilterAssemblerSubscription
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@@ -80,7 +80,7 @@ fun WatchNoteEvent(
|
||||
} else {
|
||||
// avoid observing costs if already has an event.
|
||||
val hasEvent by observeNoteHasEvent(baseNote, accountViewModel)
|
||||
CrossfadeIfEnabled(targetState = hasEvent, accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = hasEvent) {
|
||||
if (it) {
|
||||
onNoteEventFound()
|
||||
} else {
|
||||
|
||||
@@ -99,6 +99,7 @@ import com.vitorpamplona.amethyst.commons.resources.zap_type_private
|
||||
import com.vitorpamplona.amethyst.commons.resources.zap_type_private_explainer
|
||||
import com.vitorpamplona.amethyst.commons.resources.zap_type_public
|
||||
import com.vitorpamplona.amethyst.commons.resources.zap_type_public_explainer
|
||||
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.TopBarWithBackButton
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.buttons.CloseButton
|
||||
@@ -113,7 +114,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.service.ZapPaymentHandler
|
||||
import com.vitorpamplona.amethyst.ui.components.toasts.multiline.UserBasedErrorMessage
|
||||
import com.vitorpamplona.amethyst.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.OnchainZapSendDialog
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
|
||||
@@ -33,6 +33,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.ZappedIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer
|
||||
|
||||
+1
@@ -46,6 +46,7 @@ import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons
|
||||
import com.vitorpamplona.amethyst.commons.hashtags.Lightning
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.clink_lightning_offer
|
||||
import com.vitorpamplona.amethyst.commons.resources.clink_offer_amount_range
|
||||
|
||||
+2
-2
@@ -47,12 +47,12 @@ import com.vitorpamplona.amethyst.commons.resources.invoice_expired
|
||||
import com.vitorpamplona.amethyst.commons.resources.lightning_invoice
|
||||
import com.vitorpamplona.amethyst.commons.resources.pay
|
||||
import com.vitorpamplona.amethyst.commons.resources.sats
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size18Modifier
|
||||
import com.vitorpamplona.amethyst.service.lnurl.CachedLnInvoiceParser
|
||||
import com.vitorpamplona.amethyst.service.lnurl.InvoiceAmount
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.components.PaymentCard
|
||||
import com.vitorpamplona.amethyst.ui.components.PaymentCardAmount
|
||||
import com.vitorpamplona.amethyst.ui.components.PaymentCardDescription
|
||||
@@ -85,7 +85,7 @@ fun MayBeInvoicePreview(
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
LoadValueFromInvoice(lnbcWord = lnbcWord) { invoiceAmount ->
|
||||
CrossfadeIfEnabled(targetState = invoiceAmount, label = "MayBeInvoicePreview", accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = invoiceAmount, label = "MayBeInvoicePreview") {
|
||||
if (it != null) {
|
||||
InvoicePreview(it.invoice, it.amount, it.description, it.expiresAt, accountViewModel)
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -95,10 +95,10 @@ import com.vitorpamplona.amethyst.commons.resources.location_picker_search_empty
|
||||
import com.vitorpamplona.amethyst.commons.resources.location_picker_search_hint
|
||||
import com.vitorpamplona.amethyst.commons.resources.location_picker_title
|
||||
import com.vitorpamplona.amethyst.commons.resources.location_picker_use_mine
|
||||
import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.service.location.ForwardGeolocation
|
||||
import com.vitorpamplona.amethyst.service.location.LocationState
|
||||
import com.vitorpamplona.amethyst.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.geohashChat.label
|
||||
import com.vitorpamplona.quartz.experimental.bitchat.geohash.GeohashChannelLevel
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeoHash
|
||||
|
||||
+1
-3
@@ -42,12 +42,12 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import coil3.compose.AsyncImage
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.richtext.RichTextParser
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewState
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.state.produceCachedState
|
||||
import com.vitorpamplona.amethyst.model.UrlCachedPreviewer
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.VideoView
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.components.ClickableUrl
|
||||
import com.vitorpamplona.amethyst.ui.components.DisplayUrlWithLoadingSymbol
|
||||
import com.vitorpamplona.amethyst.ui.components.UrlPreviewCard
|
||||
@@ -217,7 +217,6 @@ private fun MyLoadUrlPreviewDirect(
|
||||
CrossfadeIfEnabled(
|
||||
targetState = urlPreviewState,
|
||||
label = "UrlPreview",
|
||||
accountViewModel = accountViewModel,
|
||||
) { state ->
|
||||
when (state) {
|
||||
is UrlPreviewState.Loaded -> {
|
||||
@@ -286,7 +285,6 @@ private fun MyLoadUrlPreviewDirectFillWidth(
|
||||
CrossfadeIfEnabled(
|
||||
targetState = urlPreviewState,
|
||||
label = "UrlPreview",
|
||||
accountViewModel = accountViewModel,
|
||||
) { state ->
|
||||
when (state) {
|
||||
is UrlPreviewState.Loaded -> {
|
||||
|
||||
@@ -26,6 +26,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.forked_from
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
|
||||
+1
-1
@@ -70,10 +70,10 @@ import com.vitorpamplona.amethyst.commons.resources.timestamp_it
|
||||
import com.vitorpamplona.amethyst.commons.resources.timestamp_pending
|
||||
import com.vitorpamplona.amethyst.commons.resources.unfollow
|
||||
import com.vitorpamplona.amethyst.commons.resources.unpin_from_profile
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.LightRedColor
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.ui.note.QuickActionAlertDialogOneButton
|
||||
import com.vitorpamplona.amethyst.ui.note.copyNoteTextAction
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
+1
-1
@@ -76,6 +76,7 @@ import com.vitorpamplona.amethyst.commons.resources.lightning_invoice
|
||||
import com.vitorpamplona.amethyst.commons.resources.post_anonymously
|
||||
import com.vitorpamplona.amethyst.commons.resources.what_s_on_your_mind
|
||||
import com.vitorpamplona.amethyst.commons.resources.zapraiser
|
||||
import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.PostingTopBar
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.ContentSensitivityExplainer
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.MarkAsSensitiveButton
|
||||
@@ -103,7 +104,6 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.TakePictureButton
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton
|
||||
import com.vitorpamplona.amethyst.ui.components.getActivity
|
||||
import com.vitorpamplona.amethyst.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
|
||||
import com.vitorpamplona.amethyst.ui.note.BaseUserPicture
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||
|
||||
@@ -80,6 +80,7 @@ import coil3.compose.AsyncImage
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.model.EmptyTagList
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.app_definition_available_on
|
||||
@@ -101,16 +102,16 @@ import com.vitorpamplona.amethyst.commons.resources.profile_banner
|
||||
import com.vitorpamplona.amethyst.commons.resources.profile_image
|
||||
import com.vitorpamplona.amethyst.commons.richtext.RichTextParser
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.LinkIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size16Modifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote
|
||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
|
||||
import com.vitorpamplona.amethyst.ui.components.ZoomableImageDialog
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.note.BaseUserPicture
|
||||
import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote
|
||||
|
||||
@@ -43,6 +43,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.LoadThumbAndThenVideoView
|
||||
|
||||
@@ -63,6 +63,7 @@ import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.accept_badge
|
||||
import com.vitorpamplona.amethyst.commons.resources.award_badge
|
||||
|
||||
@@ -32,6 +32,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
|
||||
+1
@@ -33,6 +33,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HalfVertPadding
|
||||
|
||||
@@ -46,6 +46,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ChessChallenge
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ui.ChessGameViewer
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
|
||||
@@ -62,6 +62,7 @@ import com.vitorpamplona.amethyst.commons.model.EmptyTagList
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.about_us
|
||||
|
||||
@@ -49,11 +49,11 @@ import androidx.compose.ui.unit.dp
|
||||
import coil3.compose.AsyncImage
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.AddButton
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.RemoveButton
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size35Modifier
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteAndMap
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.components.ShowMoreButton
|
||||
import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote
|
||||
import com.vitorpamplona.amethyst.ui.note.getGradient
|
||||
@@ -189,7 +189,7 @@ private fun EmojiListOptions(
|
||||
usersEmojiList.event?.isTaggedAddressableNote(emojiPackNote.idHex)
|
||||
}
|
||||
|
||||
CrossfadeIfEnabled(targetState = hasAddedThis, label = "EmojiListOptions", accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = hasAddedThis, label = "EmojiListOptions") {
|
||||
if (it != true) {
|
||||
AddButton(modifier = Modifier.padding(start = 3.dp)) { accountViewModel.addEmojiPack(emojiPackNote) }
|
||||
} else {
|
||||
|
||||
@@ -56,6 +56,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.AddressableNote
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for
|
||||
|
||||
@@ -30,8 +30,8 @@ import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaLocalImage
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaLocalVideo
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.components.LoadNote
|
||||
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
|
||||
import com.vitorpamplona.amethyst.ui.components.ZoomableContentView
|
||||
@@ -110,7 +110,7 @@ private fun ObserverAndRenderNIP95(
|
||||
mutableStateOf<BaseMediaContent?>(newContent)
|
||||
}
|
||||
|
||||
CrossfadeIfEnabled(targetState = content, accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = content) {
|
||||
if (it != null) {
|
||||
SensitivityWarning(note = header, accountViewModel = accountViewModel) {
|
||||
ZoomableContentView(
|
||||
|
||||
@@ -43,6 +43,7 @@ import androidx.compose.ui.unit.sp
|
||||
import com.vitorpamplona.amethyst.commons.model.EmptyTagList
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.follow_list_item_label
|
||||
|
||||
@@ -48,6 +48,7 @@ import com.vitorpamplona.amethyst.commons.resources.copy_to_clipboard
|
||||
import com.vitorpamplona.amethyst.commons.resources.fundraiser_ends
|
||||
import com.vitorpamplona.amethyst.commons.resources.fundraiser_onchain_donation
|
||||
import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.CopyIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
@@ -55,7 +56,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size18Modifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier
|
||||
import com.vitorpamplona.amethyst.ui.components.MyAsyncImage
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeaderBackground
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags
|
||||
|
||||
@@ -47,6 +47,7 @@ import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.highlights.HighlightQuote
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav
|
||||
@@ -54,6 +55,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.HighlightQuoteIndent
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.HighlightQuoteSpacing
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.HighlightedQuote
|
||||
import com.vitorpamplona.amethyst.commons.ui.richtext.CreateClickableTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo
|
||||
|
||||
@@ -48,10 +48,12 @@ import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.live_stream_has_ended
|
||||
import com.vitorpamplona.amethyst.commons.resources.live_stream_is_offline
|
||||
import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
@@ -61,7 +63,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.VideoView
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.components.MyAsyncImage
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture
|
||||
@@ -164,7 +165,7 @@ fun RenderLiveActivityEventInner(
|
||||
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
|
||||
CrossfadeIfEnabled(targetState = status, label = "RenderLiveActivityEventInner", accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = status, label = "RenderLiveActivityEventInner") {
|
||||
when (it) {
|
||||
StatusTag.STATUS.LIVE -> {
|
||||
media?.let {
|
||||
|
||||
@@ -48,6 +48,7 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.core.net.toUri
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.meeting_room_in_space
|
||||
import com.vitorpamplona.amethyst.commons.resources.meeting_room_in_space_unknown
|
||||
@@ -64,6 +65,7 @@ import com.vitorpamplona.amethyst.commons.resources.nest_presence_listening
|
||||
import com.vitorpamplona.amethyst.commons.resources.nest_presence_on_stage
|
||||
import com.vitorpamplona.amethyst.commons.resources.nest_presence_raised_hand
|
||||
import com.vitorpamplona.amethyst.commons.resources.nest_presence_speaking
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.SmallBorder
|
||||
@@ -71,7 +73,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.SpacedBy5dp
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture
|
||||
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
|
||||
@@ -140,7 +141,7 @@ fun RenderMeetingSpaceEventInner(
|
||||
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
|
||||
CrossfadeIfEnabled(targetState = status, label = "MeetingSpaceStatus", accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = status, label = "MeetingSpaceStatus") {
|
||||
when (it) {
|
||||
MeetingSpaceStatusTag.STATUS.LIVE -> {
|
||||
MeetingSpaceOpenFlag()
|
||||
@@ -295,7 +296,7 @@ fun RenderMeetingRoomEventInner(
|
||||
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
|
||||
CrossfadeIfEnabled(targetState = status, label = "MeetingRoomStatus", accountViewModel = accountViewModel) {
|
||||
CrossfadeIfEnabled(targetState = status, label = "MeetingRoomStatus") {
|
||||
when (it) {
|
||||
StatusTag.STATUS.LIVE -> {
|
||||
media?.let {
|
||||
|
||||
@@ -71,11 +71,11 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size16Modifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.ui.note.UserPicture
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.nipBCOnchainZaps.chain.BitcoinTx
|
||||
|
||||
@@ -42,6 +42,7 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
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
|
||||
|
||||
@@ -74,6 +74,7 @@ import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.model.nip88Polls.PollResponsesCache
|
||||
import com.vitorpamplona.amethyst.commons.model.nip88Polls.TallyResults
|
||||
import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists
|
||||
|
||||
@@ -36,6 +36,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.model.EmptyTagList
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.private_conversation_notification
|
||||
|
||||
@@ -61,12 +61,14 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.number_followers
|
||||
import com.vitorpamplona.amethyst.commons.resources.profile_card_bot
|
||||
import com.vitorpamplona.amethyst.commons.resources.profile_card_follows_you
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.ShowUserButton
|
||||
import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size16Modifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp
|
||||
@@ -77,7 +79,6 @@ import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.observe
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserContactCardsFollowerCount
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowing
|
||||
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.note.BaseUserPicture
|
||||
import com.vitorpamplona.amethyst.ui.note.ObserveDisplayNip05Status
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.AddressableNote
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.publication_untitled_section
|
||||
|
||||
@@ -45,6 +45,7 @@ import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel
|
||||
import com.vitorpamplona.amethyst.commons.nip29RelayGroups.ui.RelayNameChip
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable
|
||||
|
||||
@@ -58,11 +58,11 @@ import com.vitorpamplona.amethyst.commons.resources.public_home_section
|
||||
import com.vitorpamplona.amethyst.commons.resources.public_notif_section
|
||||
import com.vitorpamplona.amethyst.commons.resources.search_relays_title
|
||||
import com.vitorpamplona.amethyst.commons.resources.trusted_relays_title
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserRelayIntoList
|
||||
import com.vitorpamplona.amethyst.ui.components.ShowMoreButton
|
||||
import com.vitorpamplona.amethyst.ui.components.util.setText
|
||||
import com.vitorpamplona.amethyst.ui.note.AddRelayButton
|
||||
import com.vitorpamplona.amethyst.ui.note.RemoveRelayButton
|
||||
import com.vitorpamplona.amethyst.ui.note.getGradient
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user