mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-06 03:38:23 +00:00
refactor: share relay exporters, zap amount text and composer nav seams
- FileSharer expect/actual (Android zips into the cache and shares via the FileProvider); RelayExporter/RelayZipExporter/RelayListCollection move to commonsUI on TextSharer/FileSharer. - rememberExtendedNav moves to commonsUI; composer screens take INav. - ZapAmountText and the NWC finder subscription move to commonsUI; QuickZapAmountRow becomes a NotePlatform slot. - ChannelNewMessageViewModel mines PoW with a monotonic deadline (KMP). - BlossomServerFinder port on AppServices for MarmotGroupIconDisplay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S7FuNBSKiyVecARSoE4B9P
This commit is contained in:
+1
-1
@@ -44,11 +44,11 @@ import com.vitorpamplona.amethyst.commons.resources.error_dialog_button_ok
|
||||
import com.vitorpamplona.amethyst.commons.resources.notify_block_relay
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.rememberExtendedNav
|
||||
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.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
|
||||
|
||||
@Composable
|
||||
fun NotifyRequestDialog(
|
||||
|
||||
@@ -24,8 +24,6 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.ObservableNav
|
||||
|
||||
@Composable
|
||||
fun rememberNav(): Nav {
|
||||
@@ -37,14 +35,3 @@ fun rememberNav(): Nav {
|
||||
Nav(navController, scope, ime)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun rememberExtendedNav(
|
||||
nav: INav,
|
||||
onBeforeNavigate: () -> Unit,
|
||||
): INav {
|
||||
val scope = rememberCoroutineScope()
|
||||
return remember(nav, scope) {
|
||||
ObservableNav(nav, scope, onBeforeNavigate)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ElevatedCard
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ProgressIndicatorDefaults
|
||||
import androidx.compose.material3.Surface
|
||||
@@ -77,7 +76,6 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.mutableLongStateOf
|
||||
@@ -95,7 +93,6 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.StrokeCap
|
||||
import androidx.compose.ui.platform.LocalClipboard
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
@@ -124,7 +121,6 @@ import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.ReactionRowAction
|
||||
import com.vitorpamplona.amethyst.commons.model.ReactionRowItem
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.ZapraiserStatus
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.payments.PaymentTargetTypes
|
||||
@@ -138,6 +134,7 @@ import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteReposts
|
||||
import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteRepostsBy
|
||||
import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteZaps
|
||||
import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription
|
||||
import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.nwc.NWCFinderFilterAssemblerSubscription
|
||||
import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.boost
|
||||
@@ -164,7 +161,6 @@ import com.vitorpamplona.amethyst.commons.resources.quick_zap_amounts
|
||||
import com.vitorpamplona.amethyst.commons.resources.quote
|
||||
import com.vitorpamplona.amethyst.commons.resources.read_only_user
|
||||
import com.vitorpamplona.amethyst.commons.resources.reload_mint_title
|
||||
import com.vitorpamplona.amethyst.commons.resources.sats_to_complete
|
||||
import com.vitorpamplona.amethyst.commons.service.ZapPaymentHandler
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.AnimatedBorderTextCornerRadius
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.ClickableBox
|
||||
@@ -181,11 +177,13 @@ import com.vitorpamplona.amethyst.commons.ui.note.ExpandMoreIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.LikeIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.LikedIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.ObserveZapAmountText
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.OutlinedZapIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.RenderBoostGallery
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.RenderLikeGallery
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.RenderReaction
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.RenderZapGallery
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.RenderZapRaiser
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.RepostIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.RepostedIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.ShareIcon
|
||||
@@ -203,10 +201,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Font14SP
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HalfDoubleVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HalfPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Height24dpFilledModifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Height4dpFilledModifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ModifierWidth3dp
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.NoSoTinyBorders
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ReactionRowExpandButton
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ReactionRowHeight
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ReactionRowHeightWithPadding
|
||||
@@ -223,11 +218,9 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size22Modifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size28Modifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.SmallBorder
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.TinyBorders
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.defaultTweenDuration
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.defaultTweenFloatSpec
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.defaultTweenIntOffsetSpec
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.fundraiserProgressColor
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.reactionBox
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ripple24dp
|
||||
@@ -239,7 +232,6 @@ import com.vitorpamplona.amethyst.model.zap.CashuRailStatus
|
||||
import com.vitorpamplona.amethyst.model.zap.RailCapability
|
||||
import com.vitorpamplona.amethyst.model.zap.RailCapabilityResolver
|
||||
import com.vitorpamplona.amethyst.service.payments.PayToAppAvailability
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.nwc.NWCFinderFilterAssemblerSubscription
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.MAX_VOICE_RECORD_SECONDS
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.RecordAudioBox
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.PaymentTargetsDialog
|
||||
@@ -268,7 +260,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.uuid.ExperimentalUuidApi
|
||||
import kotlin.uuid.Uuid
|
||||
import androidx.compose.material3.Icon as Material3Icon
|
||||
@@ -524,57 +515,6 @@ fun LoadAndDisplayZapraiser(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RenderZapRaiser(
|
||||
baseNote: Note,
|
||||
zapraiserAmount: Long,
|
||||
details: Boolean,
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
val zapsState by observeNoteZaps(baseNote, accountViewModel)
|
||||
|
||||
var zapraiserStatus by remember { mutableStateOf(ZapraiserStatus(0F, "$zapraiserAmount")) }
|
||||
|
||||
LaunchedEffect(key1 = zapsState) {
|
||||
zapsState?.note?.let {
|
||||
val newStatus = accountViewModel.calculateZapraiser(baseNote)
|
||||
if (zapraiserStatus != newStatus) {
|
||||
zapraiserStatus = newStatus
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LinearProgressIndicator(
|
||||
modifier = if (details) Height24dpFilledModifier else Height4dpFilledModifier,
|
||||
color = MaterialTheme.colorScheme.fundraiserProgressColor,
|
||||
progress = { zapraiserStatus.progress },
|
||||
gapSize = 0.dp,
|
||||
strokeCap = StrokeCap.Square,
|
||||
drawStopIndicator = {},
|
||||
)
|
||||
|
||||
if (details) {
|
||||
Box(
|
||||
contentAlignment = Center,
|
||||
modifier = TinyBorders,
|
||||
) {
|
||||
val totalPercentage by
|
||||
remember(zapraiserStatus) {
|
||||
derivedStateOf { "${(zapraiserStatus.progress * 100).roundToInt()}%" }
|
||||
}
|
||||
|
||||
Text(
|
||||
text =
|
||||
stringRes(id = Res.string.sats_to_complete, totalPercentage, zapraiserStatus.left),
|
||||
modifier = NoSoTinyBorders,
|
||||
// color = MaterialTheme.colorScheme.placeholderText,
|
||||
fontSize = Font14SP,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WatchReactionsZapsBoostsAndDisplayIfExists(
|
||||
baseNote: Note,
|
||||
@@ -1668,45 +1608,6 @@ fun ObserveZapIcon(
|
||||
inner(wasZappedByLoggedInUser)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ObserveZapAmountText(
|
||||
baseNote: Note,
|
||||
accountViewModel: AccountViewModel,
|
||||
inner: @Composable (String) -> Unit,
|
||||
) {
|
||||
val zapsState by observeNoteZaps(baseNote, accountViewModel)
|
||||
|
||||
if (zapsState?.note?.zapPayments?.isNotEmpty() == true) {
|
||||
zapsState?.note?.zapPayments?.forEach {
|
||||
if (it.value == null) {
|
||||
NWCFinderFilterAssemblerSubscription(it.key, accountViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("ProduceStateDoesNotAssignValue")
|
||||
val zapAmountTxt by
|
||||
produceState(initialValue = showAmount(baseNote.zapsAmount), key1 = zapsState) {
|
||||
zapsState?.note?.let {
|
||||
val newZapAmount = accountViewModel.calculateZapAmount(it)
|
||||
if (value != newZapAmount) {
|
||||
value = newZapAmount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner(zapAmountTxt)
|
||||
} else {
|
||||
// Include the signed-in user's own pending onchain zaps so
|
||||
// the counter reflects the optimistic value the gallery shows.
|
||||
val ownPubKey = accountViewModel.account.userProfile().pubkeyHex
|
||||
val note = zapsState?.note
|
||||
val total =
|
||||
(note?.zapsAmount ?: java.math.BigDecimal(0)) +
|
||||
java.math.BigDecimal(note?.extraOwnPendingOnchainSats(ownPubKey) ?: 0L)
|
||||
inner(showAmount(total))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoostTypeChoicePopup(
|
||||
baseNote: Note,
|
||||
|
||||
+4
-4
@@ -83,6 +83,7 @@ import com.vitorpamplona.amethyst.commons.ui.actions.uploads.SelectFromFiles
|
||||
import com.vitorpamplona.amethyst.commons.ui.actions.uploads.SelectFromGallery
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
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.BaseUserPicture
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose
|
||||
@@ -114,7 +115,6 @@ import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
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.navigation.navs.Nav
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest
|
||||
@@ -144,7 +144,7 @@ fun ReplyCommentPostScreen(
|
||||
quoteId: HexKey? = null,
|
||||
draftId: HexKey? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val postViewModel: CommentPostViewModel = viewModel()
|
||||
postViewModel.init(accountViewModel)
|
||||
@@ -184,7 +184,7 @@ fun ReplyCommentPostScreen(
|
||||
fun GenericCommentPostScreen(
|
||||
postViewModel: CommentPostViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
WatchAndLoadMyEmojiList(accountViewModel)
|
||||
|
||||
@@ -279,7 +279,7 @@ fun GenericCommentPostScreen(
|
||||
private fun GenericCommentPostBody(
|
||||
postViewModel: CommentPostViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
val audienceLists = rememberAudienceLists(accountViewModel)
|
||||
|
||||
+10
@@ -83,6 +83,7 @@ import com.vitorpamplona.amethyst.ui.note.types.RenderNamedSiteEvent as AppRende
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderRootNappletEvent as AppRenderRootNappletEvent
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderRootSiteEvent as AppRenderRootSiteEvent
|
||||
import com.vitorpamplona.amethyst.ui.note.types.RenderVoiceTrack as AppRenderVoiceTrack
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.QuickZapAmountRow as AppQuickZapAmountRow
|
||||
|
||||
/** Android's [NotePlatform]: the app's own media, map, audio, chess, git, napplet and zap composables. */
|
||||
object AndroidNotePlatform : NotePlatform {
|
||||
@@ -621,6 +622,15 @@ object AndroidNotePlatform : NotePlatform {
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun QuickZapAmountRow(
|
||||
note: Note,
|
||||
onDismiss: () -> Unit,
|
||||
onOnchainRequest: (Long?) -> Unit,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) = AppQuickZapAmountRow(note, onDismiss, onOnchainRequest, accountViewModel, nav)
|
||||
|
||||
@Composable
|
||||
override fun EditPostView(
|
||||
onClose: () -> Unit,
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.vitorpamplona.amethyst.commons.connectedApps.signers.NostrSignerPermi
|
||||
import com.vitorpamplona.amethyst.commons.favorites.FavoriteAppsRegistry
|
||||
import com.vitorpamplona.amethyst.commons.napplet.permissions.NappletPermissionLedger
|
||||
import com.vitorpamplona.amethyst.commons.service.AppServices
|
||||
import com.vitorpamplona.amethyst.commons.service.BlossomServerFinder
|
||||
import com.vitorpamplona.amethyst.commons.tor.TorSettingsFlow
|
||||
import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinNameResolver
|
||||
|
||||
@@ -49,4 +50,19 @@ object AndroidAppServices : AppServices {
|
||||
override val torSettings: TorSettingsFlow get() = Amethyst.instance.torPrefs.value
|
||||
|
||||
override val namecoinResolver: NamecoinNameResolver get() = Amethyst.instance.namecoinResolver
|
||||
|
||||
override val blossomServerFinder: BlossomServerFinder = AndroidBlossomServerFinder
|
||||
}
|
||||
|
||||
/** [BlossomServerFinder] over the app's BUD-10 resolver, read lazily (main process only). */
|
||||
private object AndroidBlossomServerFinder : BlossomServerFinder {
|
||||
override fun cachedServerUrl(blossomUri: String): String? =
|
||||
Amethyst.instance.blossomResolver
|
||||
.cachedFindServer(blossomUri)
|
||||
?.serverUrl
|
||||
|
||||
override suspend fun findServerUrl(blossomUri: String): String? =
|
||||
Amethyst.instance.blossomResolver
|
||||
.findServers(blossomUri)
|
||||
?.serverUrl
|
||||
}
|
||||
|
||||
+1
-107
@@ -49,7 +49,6 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -59,7 +58,6 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.model.concord.ConcordChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel
|
||||
@@ -69,16 +67,13 @@ import com.vitorpamplona.amethyst.commons.resources.buzz_edit_message
|
||||
import com.vitorpamplona.amethyst.commons.resources.chat_delivery_details_title
|
||||
import com.vitorpamplona.amethyst.commons.resources.edit_draft
|
||||
import com.vitorpamplona.amethyst.commons.resources.edit_message
|
||||
import com.vitorpamplona.amethyst.commons.resources.error_dialog_zap_error
|
||||
import com.vitorpamplona.amethyst.commons.resources.more_options
|
||||
import com.vitorpamplona.amethyst.commons.resources.no_wallet_found
|
||||
import com.vitorpamplona.amethyst.commons.resources.quick_action_delete_dialog_btn
|
||||
import com.vitorpamplona.amethyst.commons.resources.quick_action_request_deletion_alert_title
|
||||
import com.vitorpamplona.amethyst.commons.resources.relay_group_pin_message
|
||||
import com.vitorpamplona.amethyst.commons.resources.relay_group_unpin_message
|
||||
import com.vitorpamplona.amethyst.commons.resources.reply_description
|
||||
import com.vitorpamplona.amethyst.commons.resources.show_less
|
||||
import com.vitorpamplona.amethyst.commons.service.ZapPaymentHandler
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.ClickableBox
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.ChangeReactionIcon
|
||||
@@ -93,9 +88,9 @@ import com.vitorpamplona.amethyst.commons.ui.note.elements.ShareOptionsBottomShe
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.elements.noteActionSections
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.elements.observeBookmarksFollowsAndAccount
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.platform.EditPostView
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.platform.QuickZapAmountRow
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.report.ReportNoteDialog
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.OnchainZapSendDialog
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.navigateToReloadMint
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size28Modifier
|
||||
@@ -104,17 +99,11 @@ import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.reactionBox
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.selectedReactionBoxModifier
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.note.ZapAmountChoiceGrid
|
||||
import com.vitorpamplona.amethyst.ui.note.observeZapRailCapability
|
||||
import com.vitorpamplona.amethyst.ui.note.payViaIntentOrManualSplit
|
||||
import com.vitorpamplona.quartz.buzz.stream.StreamMessageV2Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip22Comments.CommentEvent
|
||||
import com.vitorpamplona.quartz.nipC7Chats.ChatEvent
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableSet
|
||||
import kotlin.uuid.ExperimentalUuidApi
|
||||
|
||||
// null amount = open the on-chain dialog with no prefill.
|
||||
@Immutable
|
||||
@@ -622,98 +611,3 @@ private fun QuickReactionRow(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The user's zap presets unpacked as rail-aware amount chips (same grid the zap
|
||||
* amount popup shows), firing directly from the sheet. Lightning/cashu zaps
|
||||
* dismiss immediately — errors surface as toasts and the receipt lands on the
|
||||
* bubble's sats chip; on-chain amounts hand off to the dialog hosted by the sheet.
|
||||
*/
|
||||
@OptIn(ExperimentalUuidApi::class)
|
||||
@Composable
|
||||
private fun QuickZapAmountRow(
|
||||
note: Note,
|
||||
onDismiss: () -> Unit,
|
||||
onOnchainRequest: (Long?) -> Unit,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val noWalletFoundStr = stringRes(Res.string.no_wallet_found)
|
||||
val zapAmountChoices by
|
||||
accountViewModel.account.settings.syncedSettings.zaps.zapAmountChoices
|
||||
.collectAsStateWithLifecycle()
|
||||
|
||||
val amountChoices = remember(zapAmountChoices) { zapAmountChoices.distinct().toImmutableList() }
|
||||
if (amountChoices.isEmpty()) return
|
||||
|
||||
val railCapability =
|
||||
observeZapRailCapability(
|
||||
baseNote = note,
|
||||
accountViewModel = accountViewModel,
|
||||
// Onchain zap events are public and would e-tag the rumor id.
|
||||
onchainSupported = !note.isPrivateRumor(),
|
||||
)
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
val onError = { _: String, message: String, user: User? ->
|
||||
// Payment failed — drop the optimistic "zapping" indicator on the bubble.
|
||||
accountViewModel.endZapInFlight(note.idHex)
|
||||
accountViewModel.toastManager.toast(Res.string.error_dialog_zap_error, message, user)
|
||||
}
|
||||
|
||||
val onPayViaIntent = { payables: ImmutableList<ZapPaymentHandler.Payable> ->
|
||||
// Handoff to an external wallet: we can't observe whether it completes, so clear
|
||||
// the optimistic indicator rather than leave it spinning forever.
|
||||
accountViewModel.endZapInFlight(note.idHex)
|
||||
payViaIntentOrManualSplit(payables, context, noWalletFoundStr, accountViewModel, nav)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
ZapAmountChoiceGrid(
|
||||
amountChoices = amountChoices,
|
||||
railCapability = railCapability,
|
||||
onLightningZap = { amountInSats ->
|
||||
// Show a pending zap chip on the bubble immediately; it settles into the
|
||||
// real sats chip once the receipt lands (or clears on error/timeout).
|
||||
accountViewModel.markZapInFlight(note.idHex)
|
||||
accountViewModel.zap(
|
||||
note,
|
||||
amountInSats * 1000,
|
||||
null,
|
||||
"",
|
||||
true,
|
||||
onError,
|
||||
{ },
|
||||
onPayViaIntent,
|
||||
)
|
||||
onDismiss()
|
||||
},
|
||||
onNutzap = { amountInSats ->
|
||||
accountViewModel.markZapInFlight(note.idHex)
|
||||
accountViewModel.sendNutzap(
|
||||
baseNote = note,
|
||||
amountSats = amountInSats,
|
||||
message = "",
|
||||
onError = onError,
|
||||
onProgress = { },
|
||||
)
|
||||
onDismiss()
|
||||
},
|
||||
onOnchainAmount = onOnchainRequest,
|
||||
onReloadNutzap = { amount ->
|
||||
navigateToReloadMint(accountViewModel, nav, note, amount)
|
||||
onDismiss()
|
||||
},
|
||||
onChangeAmount = {
|
||||
nav.nav(Route.UpdateZapAmount())
|
||||
onDismiss()
|
||||
},
|
||||
// Hands off to another app; the sheet must not stay stacked behind it.
|
||||
onHandedOff = onDismiss,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -56,6 +56,7 @@ import com.vitorpamplona.amethyst.commons.model.navigation.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.LocalInlineQuoteRenderer
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.RenderZapRaiser
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.WatchBlockAndReport
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.WatchNoteEvent
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.DisplayZapSplits
|
||||
@@ -66,7 +67,6 @@ import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.Re
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.ReactionRowZapraiser
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.note.RenderZapRaiser
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderBuzzActivityRow
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderBuzzDiff
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderBuzzEditedNote
|
||||
|
||||
+1
-1
@@ -66,6 +66,7 @@ import com.vitorpamplona.amethyst.commons.resources.chat_minichat_reply_count
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.AnimatedBorderTextCornerRadius
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.LikedIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.ObserveZapAmountText
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.ZappedIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.richtext.InLineIconRenderer
|
||||
@@ -76,7 +77,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.grayText
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.subtleBorder
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.note.ObserveZapAmountText
|
||||
import com.vitorpamplona.quartz.nip30CustomEmoji.CustomEmoji
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
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.Route
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.error_dialog_zap_error
|
||||
import com.vitorpamplona.amethyst.commons.resources.no_wallet_found
|
||||
import com.vitorpamplona.amethyst.commons.service.ZapPaymentHandler
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.navigateToReloadMint
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.note.ZapAmountChoiceGrid
|
||||
import com.vitorpamplona.amethyst.ui.note.observeZapRailCapability
|
||||
import com.vitorpamplona.amethyst.ui.note.payViaIntentOrManualSplit
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlin.uuid.ExperimentalUuidApi
|
||||
|
||||
/**
|
||||
* The user's zap presets unpacked as rail-aware amount chips (same grid the zap
|
||||
* amount popup shows), firing directly from the sheet. Lightning/cashu zaps
|
||||
* dismiss immediately — errors surface as toasts and the receipt lands on the
|
||||
* bubble's sats chip; on-chain amounts hand off to the dialog hosted by the sheet.
|
||||
*/
|
||||
@OptIn(ExperimentalUuidApi::class)
|
||||
@Composable
|
||||
fun QuickZapAmountRow(
|
||||
note: Note,
|
||||
onDismiss: () -> Unit,
|
||||
onOnchainRequest: (Long?) -> Unit,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val noWalletFoundStr = stringRes(Res.string.no_wallet_found)
|
||||
val zapAmountChoices by
|
||||
accountViewModel.account.settings.syncedSettings.zaps.zapAmountChoices
|
||||
.collectAsStateWithLifecycle()
|
||||
|
||||
val amountChoices = remember(zapAmountChoices) { zapAmountChoices.distinct().toImmutableList() }
|
||||
if (amountChoices.isEmpty()) return
|
||||
|
||||
val railCapability =
|
||||
observeZapRailCapability(
|
||||
baseNote = note,
|
||||
accountViewModel = accountViewModel,
|
||||
// Onchain zap events are public and would e-tag the rumor id.
|
||||
onchainSupported = !note.isPrivateRumor(),
|
||||
)
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
val onError = { _: String, message: String, user: User? ->
|
||||
// Payment failed — drop the optimistic "zapping" indicator on the bubble.
|
||||
accountViewModel.endZapInFlight(note.idHex)
|
||||
accountViewModel.toastManager.toast(Res.string.error_dialog_zap_error, message, user)
|
||||
}
|
||||
|
||||
val onPayViaIntent = { payables: ImmutableList<ZapPaymentHandler.Payable> ->
|
||||
// Handoff to an external wallet: we can't observe whether it completes, so clear
|
||||
// the optimistic indicator rather than leave it spinning forever.
|
||||
accountViewModel.endZapInFlight(note.idHex)
|
||||
payViaIntentOrManualSplit(payables, context, noWalletFoundStr, accountViewModel, nav)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
ZapAmountChoiceGrid(
|
||||
amountChoices = amountChoices,
|
||||
railCapability = railCapability,
|
||||
onLightningZap = { amountInSats ->
|
||||
// Show a pending zap chip on the bubble immediately; it settles into the
|
||||
// real sats chip once the receipt lands (or clears on error/timeout).
|
||||
accountViewModel.markZapInFlight(note.idHex)
|
||||
accountViewModel.zap(
|
||||
note,
|
||||
amountInSats * 1000,
|
||||
null,
|
||||
"",
|
||||
true,
|
||||
onError,
|
||||
{ },
|
||||
onPayViaIntent,
|
||||
)
|
||||
onDismiss()
|
||||
},
|
||||
onNutzap = { amountInSats ->
|
||||
accountViewModel.markZapInFlight(note.idHex)
|
||||
accountViewModel.sendNutzap(
|
||||
baseNote = note,
|
||||
amountSats = amountInSats,
|
||||
message = "",
|
||||
onError = onError,
|
||||
onProgress = { },
|
||||
)
|
||||
onDismiss()
|
||||
},
|
||||
onOnchainAmount = onOnchainRequest,
|
||||
onReloadNutzap = { amount ->
|
||||
navigateToReloadMint(accountViewModel, nav, note, amount)
|
||||
onDismiss()
|
||||
},
|
||||
onChangeAmount = {
|
||||
nav.nav(Route.UpdateZapAmount())
|
||||
onDismiss()
|
||||
},
|
||||
// Hands off to another app; the sheet must not stay stacked behind it.
|
||||
onHandedOff = onDismiss,
|
||||
)
|
||||
}
|
||||
}
|
||||
+6
-5
@@ -24,9 +24,10 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.commons.model.marmotGroups.MarmotGroupImage
|
||||
import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo
|
||||
import com.vitorpamplona.amethyst.commons.service.BlossomServerFinder
|
||||
import com.vitorpamplona.amethyst.commons.ui.platform.LocalAppServices
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.quartz.marmot.appComponents.GroupAvatarUrlV1
|
||||
import com.vitorpamplona.quartz.marmot.appComponents.MarmotWebUrl
|
||||
@@ -43,7 +44,7 @@ import com.vitorpamplona.quartz.nipB7Blossom.BlossomUri
|
||||
*
|
||||
* The blob is content-addressed on Blossom by [MarmotGroupImage.hash]; the canonical
|
||||
* scheme stores only the hash, and the icon usually lives on the *uploader's* Blossom
|
||||
* server rather than the viewer's. So we resolve it through [Amethyst.blossomResolver],
|
||||
* server rather than the viewer's. So we resolve it through the app's BUD-10 resolver ([BlossomServerFinder]),
|
||||
* which probes the viewer's default server (passed as a first-try `xs` hint) and the
|
||||
* group admins' configured servers (via their pubkeys as `as` authors, BUD-03). While
|
||||
* that async probe runs, we optimistically load from the viewer's default server so the
|
||||
@@ -77,9 +78,9 @@ fun rememberMarmotGroupIconUrl(
|
||||
).toUriString()
|
||||
}
|
||||
|
||||
val resolver = Amethyst.instance.blossomResolver
|
||||
val url by produceState(resolver.cachedFindServer(blossomUri)?.serverUrl ?: fallbackUrl, blossomUri) {
|
||||
value = resolver.findServers(blossomUri)?.serverUrl ?: fallbackUrl
|
||||
val finder = LocalAppServices.current.blossomServerFinder
|
||||
val url by produceState(finder.cachedServerUrl(blossomUri) ?: fallbackUrl, blossomUri) {
|
||||
value = finder.findServerUrl(blossomUri) ?: fallbackUrl
|
||||
}
|
||||
|
||||
val cipher = remember(image) { MarmotGroupImageCipher(image.key, image.nonce) }
|
||||
|
||||
+2
-3
@@ -125,7 +125,6 @@ import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.TakePictureButton
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton
|
||||
import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.invoice.NewPostInvoiceRequest
|
||||
@@ -148,7 +147,7 @@ fun NewGroupDMScreen(
|
||||
message: String? = null,
|
||||
attachment: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
NewGroupDMScreen(message, attachment?.ifBlank { null }?.toUri(), accountViewModel, nav)
|
||||
}
|
||||
@@ -159,7 +158,7 @@ fun NewGroupDMScreen(
|
||||
message: String? = null,
|
||||
attachment: Uri? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val postViewModel: ChatNewMessageViewModel = viewModel()
|
||||
postViewModel.init(accountViewModel)
|
||||
|
||||
+5
-4
@@ -136,6 +136,8 @@ import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlin.time.TimeSource
|
||||
|
||||
@Stable
|
||||
open class ChannelNewMessageViewModel :
|
||||
@@ -465,10 +467,9 @@ open class ChannelNewMessageViewModel :
|
||||
val mined =
|
||||
withContext(Dispatchers.Default) {
|
||||
// Bitchat mines 8 bits by default; cap the effort so a slow device still sends.
|
||||
val deadline = System.nanoTime() + 2_000_000_000L
|
||||
val threads = Runtime.getRuntime().availableProcessors().coerceAtLeast(1)
|
||||
val started = TimeSource.Monotonic.markNow()
|
||||
runCatching {
|
||||
PoWMiner.mine(template, pubKeyHex, 8, threads, isActive = { System.nanoTime() < deadline })
|
||||
PoWMiner.mine(template, pubKeyHex, 8, account.powMinerWorkers(), isActive = { started.elapsedNow() < 2.seconds })
|
||||
}.getOrDefault(template)
|
||||
}
|
||||
|
||||
@@ -1051,7 +1052,7 @@ open class ChannelNewMessageViewModel :
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
Log.d("Init") { "OnCleared: ${this.javaClass.simpleName}" }
|
||||
Log.d("Init") { "OnCleared: ${this::class.simpleName}" }
|
||||
}
|
||||
|
||||
fun updateZapPercentage(
|
||||
|
||||
+3
-3
@@ -107,6 +107,7 @@ import com.vitorpamplona.amethyst.commons.ui.actions.uploads.SelectFromGallery
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
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.ContentSensitivityExplainer
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.MarkAsSensitiveButton
|
||||
@@ -133,7 +134,6 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.TakePictureButton
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton
|
||||
import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
|
||||
import com.vitorpamplona.amethyst.ui.components.markdown.RenderContentAsMarkdown
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest
|
||||
@@ -150,7 +150,7 @@ fun LongFormPostScreen(
|
||||
draftId: HexKey? = null,
|
||||
versionId: HexKey? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val postViewModel: LongFormPostViewModel = viewModel()
|
||||
postViewModel.init(accountViewModel)
|
||||
@@ -214,7 +214,7 @@ fun LongFormPostScreen(
|
||||
private fun MarkdownPostScreenBody(
|
||||
postViewModel: LongFormPostViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
Column(
|
||||
|
||||
+1
-2
@@ -80,7 +80,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightPa
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.TakePictureButton
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest
|
||||
@@ -103,7 +102,7 @@ fun NewProductScreen(
|
||||
quoteId: HexKey? = null,
|
||||
draftId: HexKey? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val postViewModel: NewProductViewModel = viewModel()
|
||||
postViewModel.init(accountViewModel)
|
||||
|
||||
+2
-2
@@ -28,8 +28,8 @@ import androidx.core.net.toUri
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.service.uploads.SelectedMedia
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
|
||||
import com.vitorpamplona.amethyst.ui.note.nip22Comments.CommentPostViewModel
|
||||
import com.vitorpamplona.amethyst.ui.note.nip22Comments.GenericCommentPostScreen
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
@@ -47,7 +47,7 @@ fun GeoHashPostScreen(
|
||||
quoteId: HexKey? = null,
|
||||
draftId: HexKey? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val postViewModel: CommentPostViewModel = viewModel()
|
||||
postViewModel.init(accountViewModel)
|
||||
|
||||
+2
-2
@@ -28,8 +28,8 @@ import androidx.core.net.toUri
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.service.uploads.SelectedMedia
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
|
||||
import com.vitorpamplona.amethyst.ui.note.nip22Comments.CommentPostViewModel
|
||||
import com.vitorpamplona.amethyst.ui.note.nip22Comments.GenericCommentPostScreen
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
@@ -47,7 +47,7 @@ fun HashtagPostScreen(
|
||||
quoteId: HexKey? = null,
|
||||
draftId: HexKey? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val postViewModel: CommentPostViewModel = viewModel()
|
||||
postViewModel.init(accountViewModel)
|
||||
|
||||
+2
-2
@@ -72,6 +72,7 @@ import com.vitorpamplona.amethyst.commons.resources.new_highlight_passage_placeh
|
||||
import com.vitorpamplona.amethyst.commons.resources.new_highlight_source_label
|
||||
import com.vitorpamplona.amethyst.commons.resources.new_highlight_title
|
||||
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.NoteCompose
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList
|
||||
@@ -80,7 +81,6 @@ import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightPage
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.messagefield.MessageField
|
||||
|
||||
@@ -111,7 +111,7 @@ fun NewHighlightScreen(
|
||||
sourceEventId: String? = null,
|
||||
author: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val postViewModel: NewHighlightPostViewModel = viewModel()
|
||||
postViewModel.init(accountViewModel)
|
||||
|
||||
+4
-4
@@ -114,6 +114,7 @@ import com.vitorpamplona.amethyst.commons.ui.actions.uploads.SelectFromFiles
|
||||
import com.vitorpamplona.amethyst.commons.ui.actions.uploads.SelectFromGallery
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
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.BaseUserPicture
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose
|
||||
@@ -156,7 +157,6 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.VoiceAnonymizationSection
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.VoiceMessagePreview
|
||||
import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
|
||||
import com.vitorpamplona.amethyst.ui.components.getActivity
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest
|
||||
@@ -195,7 +195,7 @@ fun ShortNotePostScreen(
|
||||
groupThreadId: HexKey? = null,
|
||||
groupThreadRelayUrl: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val postViewModel: ShortNotePostViewModel = viewModel()
|
||||
postViewModel.init(accountViewModel)
|
||||
@@ -269,7 +269,7 @@ fun ShortNotePostScreen(
|
||||
internal fun NewPostScreenInner(
|
||||
postViewModel: ShortNotePostViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
WatchAndLoadMyEmojiList(accountViewModel)
|
||||
|
||||
@@ -324,7 +324,7 @@ internal fun NewPostScreenInner(
|
||||
private fun NewPostScreenBody(
|
||||
postViewModel: ShortNotePostViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
val audienceLists = rememberAudienceLists(accountViewModel)
|
||||
|
||||
+3
-3
@@ -40,6 +40,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
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.NoteCompose
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.types.ReplyRenderType
|
||||
@@ -51,7 +52,6 @@ import com.vitorpamplona.amethyst.ui.actions.mediaServers.FileServerSelectionRow
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.UploadProgressIndicator
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.VoiceAnonymizationSection
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.VoiceMessagePreview
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@@ -62,7 +62,7 @@ fun VoiceReplyScreen(
|
||||
duration: Int,
|
||||
amplitudesJson: String,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val viewModel: VoiceReplyViewModel = viewModel()
|
||||
|
||||
@@ -107,7 +107,7 @@ fun VoiceReplyScreen(
|
||||
private fun VoiceReplyScreenBody(
|
||||
viewModel: VoiceReplyViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
|
||||
+1
-2
@@ -64,13 +64,12 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.PostingTopBar
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun NewGoalScreen(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val goalViewModel: NewGoalViewModel = viewModel()
|
||||
goalViewModel.init(accountViewModel)
|
||||
|
||||
+1
-2
@@ -94,7 +94,6 @@ import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.TakePictureButton
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton
|
||||
import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.invoice.NewPostInvoiceRequest
|
||||
@@ -118,7 +117,7 @@ fun NewPublicMessageScreen(
|
||||
replyId: HexKey? = null,
|
||||
draftId: HexKey? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val postViewModel: NewPublicMessageViewModel = viewModel()
|
||||
postViewModel.init(accountViewModel)
|
||||
|
||||
+2
-2
@@ -26,8 +26,8 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.NewPostScreenInner
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.ShortNotePostViewModel
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
@@ -39,7 +39,7 @@ fun PollPostScreen(
|
||||
message: String? = null,
|
||||
draftId: HexKey? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val postViewModel: ShortNotePostViewModel = viewModel()
|
||||
postViewModel.init(accountViewModel)
|
||||
|
||||
+9
-7
@@ -40,7 +40,6 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.commons.defaults.DefaultDMRelayList
|
||||
@@ -87,9 +86,14 @@ import com.vitorpamplona.amethyst.commons.resources.trusted_section_explainer
|
||||
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.rememberFileSharer
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.rememberTextSharer
|
||||
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.screen.loggedIn.relays.common.RelayExporter
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.RelayListCollection
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.RelayZipExporter
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding
|
||||
@@ -102,9 +106,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.blocked.BlockedRelay
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.blocked.renderBlockedItems
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.broadcast.BroadcastRelayListViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.broadcast.renderBroadcastItems
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayExporter
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayListCollection
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayZipExporter
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.connected.ConnectedRelayListViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.connected.renderConnectedItems
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.dm.DMRelayListViewModel
|
||||
@@ -621,7 +622,8 @@ fun SettingsCategoryWithButton(
|
||||
@Composable
|
||||
fun ExportDropdownMenu(collection: () -> RelayListCollection) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
val context = LocalContext.current
|
||||
val textSharer = rememberTextSharer()
|
||||
val fileSharer = rememberFileSharer()
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
IconButton(onClick = { expanded = true }) {
|
||||
@@ -642,14 +644,14 @@ fun ExportDropdownMenu(collection: () -> RelayListCollection) {
|
||||
text = stringRes(Res.string.export_as_text),
|
||||
) {
|
||||
expanded = false
|
||||
scope.launch { RelayExporter(context).export(collection()) }
|
||||
scope.launch { RelayExporter(textSharer).export(collection()) }
|
||||
}
|
||||
M3ActionRow(
|
||||
icon = MaterialSymbols.FolderZip,
|
||||
text = stringRes(Res.string.export_as_zip),
|
||||
) {
|
||||
expanded = false
|
||||
scope.launch { RelayZipExporter(context).export(collection()) }
|
||||
scope.launch { RelayZipExporter(fileSharer).export(collection()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -33,6 +33,7 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.RelayUrlEditField
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
|
||||
@@ -41,7 +42,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
|
||||
|
||||
@Composable
|
||||
|
||||
+1
-1
@@ -33,6 +33,7 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.RelayUrlEditField
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
|
||||
@@ -41,7 +42,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
|
||||
|
||||
@Composable
|
||||
|
||||
+1
-1
@@ -41,12 +41,12 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.active_subs_title
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
|
||||
|
||||
@Composable
|
||||
|
||||
+1
-1
@@ -34,6 +34,7 @@ import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.RelayUrlEditField
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
|
||||
@@ -42,7 +43,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
|
||||
|
||||
+1
-1
@@ -33,6 +33,7 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.RelayUrlEditField
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
|
||||
@@ -41,7 +42,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
|
||||
|
||||
@Composable
|
||||
|
||||
+1
-1
@@ -34,6 +34,7 @@ import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.RelayUrlEditField
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
|
||||
@@ -42,7 +43,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
|
||||
|
||||
+1
-1
@@ -34,6 +34,7 @@ import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.RelayUrlEditField
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
|
||||
@@ -42,7 +43,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
|
||||
|
||||
+1
-1
@@ -37,6 +37,7 @@ import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.send_kind0_to_local_relay_description
|
||||
import com.vitorpamplona.amethyst.commons.resources.send_kind0_to_local_relay_title
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.RelayUrlEditField
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
|
||||
@@ -47,7 +48,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.SettingsCategorySpacingWithHorzBorderModifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
|
||||
|
||||
@Composable
|
||||
|
||||
+1
-1
@@ -34,6 +34,7 @@ import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.RelayUrlEditField
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
|
||||
@@ -42,7 +43,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
|
||||
|
||||
+1
-1
@@ -34,6 +34,7 @@ import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.RelayUrlEditField
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
|
||||
@@ -42,7 +43,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
|
||||
|
||||
+1
-1
@@ -34,6 +34,7 @@ import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.RelayUrlEditField
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
|
||||
@@ -42,7 +43,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
|
||||
|
||||
+1
-1
@@ -34,6 +34,7 @@ import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.RelayUrlEditField
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
|
||||
@@ -42,7 +43,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
|
||||
|
||||
+1
-1
@@ -33,6 +33,7 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.RelayUrlEditField
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
|
||||
@@ -41,7 +42,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
|
||||
|
||||
@Composable
|
||||
|
||||
+2
-2
@@ -28,8 +28,8 @@ import androidx.core.net.toUri
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.service.uploads.SelectedMedia
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
|
||||
import com.vitorpamplona.amethyst.ui.note.nip22Comments.CommentPostViewModel
|
||||
import com.vitorpamplona.amethyst.ui.note.nip22Comments.GenericCommentPostScreen
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
@@ -47,7 +47,7 @@ fun UrlPostScreen(
|
||||
quoteId: HexKey? = null,
|
||||
draftId: HexKey? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
nav: INav,
|
||||
) {
|
||||
val postViewModel: CommentPostViewModel = viewModel()
|
||||
postViewModel.init(accountViewModel)
|
||||
|
||||
+3
@@ -53,4 +53,7 @@ interface AppServices {
|
||||
|
||||
/** Resolves `.bit` names and `d/`/`id/` identifiers over the configured ElectrumX servers. */
|
||||
val namecoinResolver: NamecoinNameResolver
|
||||
|
||||
/** Finds the server behind a `blossom:` URI (BUD-10). */
|
||||
val blossomServerFinder: BlossomServerFinder get() = BlossomServerFinder.None
|
||||
}
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.commons.service
|
||||
|
||||
/**
|
||||
* Resolves a BUD-10 `blossom:` URI to the URL of a server that holds the blob, probing the
|
||||
* author's (and the viewer's) Blossom servers.
|
||||
*/
|
||||
interface BlossomServerFinder {
|
||||
/** The server URL already resolved for [blossomUri], without probing. */
|
||||
fun cachedServerUrl(blossomUri: String): String?
|
||||
|
||||
/** Probes until a server answers for [blossomUri]; null when none does. */
|
||||
suspend fun findServerUrl(blossomUri: String): String?
|
||||
|
||||
/** Resolves nothing: front ends without a Blossom client yet. */
|
||||
object None : BlossomServerFinder {
|
||||
override fun cachedServerUrl(blossomUri: String): String? = null
|
||||
|
||||
override suspend fun findServerUrl(blossomUri: String): String? = null
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.commons.ui.components
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.core.content.FileProvider
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
@Composable
|
||||
actual fun rememberFileSharer(): FileSharer {
|
||||
val context = LocalContext.current
|
||||
return remember(context) {
|
||||
FileSharer { zipName, files, title ->
|
||||
val zipFile = File(context.cacheDir, zipName)
|
||||
ZipOutputStream(FileOutputStream(zipFile)).use { zip ->
|
||||
files.forEach { (name, content) ->
|
||||
zip.putNextEntry(ZipEntry(name))
|
||||
zip.write(content.toByteArray())
|
||||
zip.closeEntry()
|
||||
}
|
||||
}
|
||||
|
||||
val uri = FileProvider.getUriForFile(context, "${context.packageName}.provider", zipFile)
|
||||
|
||||
val sendIntent =
|
||||
Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
type = "application/zip"
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
putExtra(Intent.EXTRA_TITLE, title)
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
|
||||
context.startActivity(Intent.createChooser(sendIntent, title))
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.service.relayClient.reqCommand.nwc
|
||||
package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.nwc
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.commons.ui.components
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
/** Hands generated files to the platform's share sheet. */
|
||||
fun interface FileSharer {
|
||||
/**
|
||||
* Packs [files] (name to text content) into a zip named [zipName] and shares it, behind a
|
||||
* chooser titled [title] where the platform has one.
|
||||
*/
|
||||
fun shareTextFilesAsZip(
|
||||
zipName: String,
|
||||
files: List<Pair<String, String>>,
|
||||
title: String,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The platform's file sharing: Android writes the zip to its cache and shares it through the
|
||||
* app's `FileProvider`. Desktop and iOS have no share sheet wired yet and do nothing.
|
||||
*/
|
||||
@Composable
|
||||
expect fun rememberFileSharer(): FileSharer
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.commons.ui.navigation.navs
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
|
||||
/** [nav], calling [onBeforeNavigate] first on every navigation (to close a sheet or dialog). */
|
||||
@Composable
|
||||
fun rememberExtendedNav(
|
||||
nav: INav,
|
||||
onBeforeNavigate: () -> Unit,
|
||||
): INav {
|
||||
val scope = rememberCoroutineScope()
|
||||
return remember(nav, scope) {
|
||||
ObservableNav(nav, scope, onBeforeNavigate)
|
||||
}
|
||||
}
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.commons.ui.note
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment.Companion.Center
|
||||
import androidx.compose.ui.graphics.StrokeCap
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.ZapraiserStatus
|
||||
import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteZaps
|
||||
import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.nwc.NWCFinderFilterAssemblerSubscription
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.sats_to_complete
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Font14SP
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Height24dpFilledModifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Height4dpFilledModifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.NoSoTinyBorders
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.TinyBorders
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.fundraiserProgressColor
|
||||
import com.vitorpamplona.amethyst.commons.util.showAmount
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.quartz.nip57Zaps.zapraiser.zapraiserAmount
|
||||
import com.vitorpamplona.quartz.utils.BigDecimal
|
||||
import com.vitorpamplona.quartz.utils.plus
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Composable
|
||||
fun ObserveZapAmountText(
|
||||
baseNote: Note,
|
||||
accountViewModel: AccountViewModel,
|
||||
inner: @Composable (String) -> Unit,
|
||||
) {
|
||||
val zapsState by observeNoteZaps(baseNote, accountViewModel)
|
||||
|
||||
if (zapsState?.note?.zapPayments?.isNotEmpty() == true) {
|
||||
zapsState?.note?.zapPayments?.forEach {
|
||||
if (it.value == null) {
|
||||
NWCFinderFilterAssemblerSubscription(it.key, accountViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("ProduceStateDoesNotAssignValue")
|
||||
val zapAmountTxt by
|
||||
produceState(initialValue = showAmount(baseNote.zapsAmount), key1 = zapsState) {
|
||||
zapsState?.note?.let {
|
||||
val newZapAmount = accountViewModel.calculateZapAmount(it)
|
||||
if (value != newZapAmount) {
|
||||
value = newZapAmount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner(zapAmountTxt)
|
||||
} else {
|
||||
// Include the signed-in user's own pending onchain zaps so
|
||||
// the counter reflects the optimistic value the gallery shows.
|
||||
val ownPubKey = accountViewModel.account.userProfile().pubkeyHex
|
||||
val note = zapsState?.note
|
||||
val total =
|
||||
(note?.zapsAmount ?: BigDecimal(0)) +
|
||||
BigDecimal(note?.extraOwnPendingOnchainSats(ownPubKey) ?: 0L)
|
||||
inner(showAmount(total))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RenderZapRaiser(
|
||||
baseNote: Note,
|
||||
zapraiserAmount: Long,
|
||||
details: Boolean,
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
val zapsState by observeNoteZaps(baseNote, accountViewModel)
|
||||
|
||||
var zapraiserStatus by remember { mutableStateOf(ZapraiserStatus(0F, "$zapraiserAmount")) }
|
||||
|
||||
LaunchedEffect(key1 = zapsState) {
|
||||
zapsState?.note?.let {
|
||||
val newStatus = accountViewModel.calculateZapraiser(baseNote)
|
||||
if (zapraiserStatus != newStatus) {
|
||||
zapraiserStatus = newStatus
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LinearProgressIndicator(
|
||||
modifier = if (details) Height24dpFilledModifier else Height4dpFilledModifier,
|
||||
color = MaterialTheme.colorScheme.fundraiserProgressColor,
|
||||
progress = { zapraiserStatus.progress },
|
||||
gapSize = 0.dp,
|
||||
strokeCap = StrokeCap.Square,
|
||||
drawStopIndicator = {},
|
||||
)
|
||||
|
||||
if (details) {
|
||||
Box(
|
||||
contentAlignment = Center,
|
||||
modifier = TinyBorders,
|
||||
) {
|
||||
val totalPercentage by
|
||||
remember(zapraiserStatus) {
|
||||
derivedStateOf { "${(zapraiserStatus.progress * 100).roundToInt()}%" }
|
||||
}
|
||||
|
||||
Text(
|
||||
text =
|
||||
stringRes(id = Res.string.sats_to_complete, totalPercentage, zapraiserStatus.left),
|
||||
modifier = NoSoTinyBorders,
|
||||
// color = MaterialTheme.colorScheme.placeholderText,
|
||||
fontSize = Font14SP,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -426,6 +426,19 @@ interface NotePlatform {
|
||||
callbacks: ZapButtonCallbacks,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* The user's zap presets as rail-aware amount chips that zap [note] straight away (the chat
|
||||
* long-press sheet). [onOnchainRequest] hands an on-chain amount to the caller's dialog.
|
||||
*/
|
||||
@Composable
|
||||
fun QuickZapAmountRow(
|
||||
note: Note,
|
||||
onDismiss: () -> Unit,
|
||||
onOnchainRequest: (Long?) -> Unit,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {}
|
||||
|
||||
/** The editor for a new version of [edit], shown while [versionLookingAt] is on screen. */
|
||||
@Composable
|
||||
fun EditPostView(
|
||||
|
||||
+9
@@ -559,6 +559,15 @@ fun ReusableZapButton(
|
||||
callbacks: ZapButtonCallbacks = ZapButtonCallbacks(),
|
||||
) = LocalNotePlatform.current.ReusableZapButton(baseNote, accountViewModel, nav, config, callbacks)
|
||||
|
||||
@Composable
|
||||
fun QuickZapAmountRow(
|
||||
note: Note,
|
||||
onDismiss: () -> Unit,
|
||||
onOnchainRequest: (Long?) -> Unit,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) = LocalNotePlatform.current.QuickZapAmountRow(note, onDismiss, onOnchainRequest, accountViewModel, nav)
|
||||
|
||||
@Composable
|
||||
fun EditPostView(
|
||||
onClose: () -> Unit,
|
||||
|
||||
+5
-20
@@ -18,35 +18,20 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common
|
||||
package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.export_relay_settings
|
||||
import com.vitorpamplona.amethyst.commons.resources.relay_settings
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.TextSharer
|
||||
import com.vitorpamplona.amethyst.commons.ui.loadStringRes
|
||||
|
||||
class RelayExporter(
|
||||
val context: Context,
|
||||
val sharer: TextSharer,
|
||||
) {
|
||||
suspend fun export(collection: RelayListCollection) {
|
||||
val text = buildExportText(collection)
|
||||
|
||||
val sendIntent =
|
||||
Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
type = "text/plain"
|
||||
putExtra(Intent.EXTRA_TEXT, text)
|
||||
putExtra(Intent.EXTRA_TITLE, loadStringRes(Res.string.export_relay_settings))
|
||||
}
|
||||
|
||||
val shareIntent =
|
||||
Intent.createChooser(
|
||||
sendIntent,
|
||||
loadStringRes(Res.string.export_relay_settings),
|
||||
)
|
||||
context.startActivity(shareIntent)
|
||||
val title = loadStringRes(Res.string.export_relay_settings)
|
||||
sharer.share(buildExportText(collection), title, title)
|
||||
}
|
||||
|
||||
suspend fun buildExportText(collection: RelayListCollection): String {
|
||||
+1
-2
@@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common
|
||||
package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.blocked_section
|
||||
@@ -45,7 +45,6 @@ import com.vitorpamplona.amethyst.commons.resources.search_section
|
||||
import com.vitorpamplona.amethyst.commons.resources.search_section_explainer
|
||||
import com.vitorpamplona.amethyst.commons.resources.trusted_section
|
||||
import com.vitorpamplona.amethyst.commons.resources.trusted_section_explainer
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||
import org.jetbrains.compose.resources.StringResource
|
||||
|
||||
data class RelayListCollection(
|
||||
+12
-49
@@ -18,67 +18,30 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common
|
||||
package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.core.content.FileProvider
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.export_relay_settings
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.FileSharer
|
||||
import com.vitorpamplona.amethyst.commons.ui.loadStringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
/** Exports each non-empty relay section as `<section>.json` (an array of URLs) in one zip. */
|
||||
class RelayZipExporter(
|
||||
val context: Context,
|
||||
val sharer: FileSharer,
|
||||
) {
|
||||
suspend fun export(collection: RelayListCollection) {
|
||||
val zipFile = buildZipFile(collection)
|
||||
|
||||
val uri =
|
||||
FileProvider.getUriForFile(
|
||||
context,
|
||||
"${context.packageName}.provider",
|
||||
zipFile,
|
||||
)
|
||||
|
||||
val sendIntent =
|
||||
Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
type = "application/zip"
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
putExtra(Intent.EXTRA_TITLE, loadStringRes(Res.string.export_relay_settings))
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
|
||||
val shareIntent =
|
||||
Intent.createChooser(
|
||||
sendIntent,
|
||||
loadStringRes(Res.string.export_relay_settings),
|
||||
)
|
||||
context.startActivity(shareIntent)
|
||||
sharer.shareTextFilesAsZip(
|
||||
zipName = "relay_settings.zip",
|
||||
files = buildFiles(collection),
|
||||
title = loadStringRes(Res.string.export_relay_settings),
|
||||
)
|
||||
}
|
||||
|
||||
fun buildZipFile(collection: RelayListCollection): File {
|
||||
val zipFile = File(context.cacheDir, "relay_settings.zip")
|
||||
|
||||
ZipOutputStream(FileOutputStream(zipFile)).use { zip ->
|
||||
collection.sections().forEach { section ->
|
||||
if (section.relays.isNotEmpty()) {
|
||||
val json = buildJsonArray(section.relays)
|
||||
zip.putNextEntry(ZipEntry("${section.fileName}.json"))
|
||||
zip.write(json.toByteArray())
|
||||
zip.closeEntry()
|
||||
}
|
||||
}
|
||||
fun buildFiles(collection: RelayListCollection): List<Pair<String, String>> =
|
||||
collection.sections().mapNotNull { section ->
|
||||
if (section.relays.isEmpty()) null else "${section.fileName}.json" to buildJsonArray(section.relays)
|
||||
}
|
||||
|
||||
return zipFile
|
||||
}
|
||||
|
||||
private fun buildJsonArray(relays: List<BasicRelaySetupInfo>): String {
|
||||
val builder = StringBuilder()
|
||||
builder.appendLine("[")
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.commons.ui.components
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
private val NoFileSharer = FileSharer { _, _, _ -> }
|
||||
|
||||
/** No share sheet wired yet. */
|
||||
@Composable
|
||||
actual fun rememberFileSharer(): FileSharer = NoFileSharer
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.commons.ui.components
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
private val NoFileSharer = FileSharer { _, _, _ -> }
|
||||
|
||||
/** No share sheet wired yet. */
|
||||
@Composable
|
||||
actual fun rememberFileSharer(): FileSharer = NoFileSharer
|
||||
Reference in New Issue
Block a user