feat(composer): extend map location picker to all composers

Lift pickedGeoHash into the shared ILocationGrabber interface and add a shared
GeoHashPostSection composable (GPS default + "pick on map"), then wire it into
every remaining composer: long-form, classifieds, private DMs, public messages,
NIP-22 comments, channel messages, and nest messages. Each ViewModel now honors
the map-picked geohash over GPS at build time and round-trips it through drafts;
each screen renders the shared section in place of the GPS-only LocationAsHash.

The short-note composer is refactored onto the same shared section (its local
copy removed). The geohash-chat "New location channel" screen already reaches the
picker via its Teleport card, which now uses the shared, polished picker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YU8YLcjH9ALr4PgdAkGPZh
This commit is contained in:
Claude
2026-07-18 23:29:46 +00:00
parent 7b32ca1da3
commit fea9bcb8ea
16 changed files with 183 additions and 105 deletions
@@ -0,0 +1,127 @@
/*
* 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.note.creators.location
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment.Companion.CenterVertically
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.Size10dp
/**
* The shared location section for post composers. Defaults to the device-GPS flow
* ([LocationAsHash]), and adds a "pick a place on the map" action that opens
* [GeohashLocationPickerDialog] and stores the chosen geohash in
* [ILocationGrabber.pickedGeoHash] — which each composer's build step then prefers
* over the live GPS fix. Picking a place also skips the GPS permission prompt.
*
* [innerContent] is a slot for composer-specific extras rendered beneath the
* location readout (e.g. the "location-exclusive post" switch).
*/
@Composable
fun GeoHashPostSection(
model: ILocationGrabber,
innerContent: @Composable () -> Unit = {},
) {
var showPicker by remember { mutableStateOf(false) }
val picked = model.pickedGeoHash
Column(
modifier = Modifier.fillMaxWidth().padding(vertical = Size10dp, horizontal = Size10dp),
) {
if (picked != null) {
// A map-picked place: show it, and let the user clear back to GPS.
Row(verticalAlignment = CenterVertically, modifier = Modifier.fillMaxWidth()) {
Icon(
symbol = MaterialSymbols.LocationOn,
contentDescription = null,
modifier = Modifier.size(20.dp),
tint = MaterialTheme.colorScheme.primary,
)
Text(
text = stringRes(R.string.geohash_title),
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.W500,
modifier = Modifier.padding(start = 10.dp),
)
DisplayLocationInTitle(geohash = picked)
Spacer(modifier = Modifier.weight(1f))
IconButton(onClick = { model.pickedGeoHash = null }) {
Icon(
symbol = MaterialSymbols.Close,
contentDescription = stringRes(R.string.remove_location),
modifier = Modifier.size(20.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
HorizontalDivider()
innerContent()
} else {
// GPS mode (unchanged): current device location + the composer's extras.
LocationAsHash(model, innerContent)
}
TextButton(onClick = { showPicker = true }, modifier = Modifier.padding(top = 4.dp)) {
Icon(
symbol = MaterialSymbols.LocationOn,
contentDescription = null,
modifier = Modifier.size(18.dp),
tint = MaterialTheme.colorScheme.primary,
)
Text(
text = stringRes(if (picked != null) R.string.location_change_place else R.string.location_pick_on_map),
modifier = Modifier.padding(start = 6.dp),
)
}
}
if (showPicker) {
GeohashLocationPickerDialog(
initialGeohash = picked,
onDismiss = { showPicker = false },
onConfirm = { cell ->
model.pickedGeoHash = cell
showPicker = false
},
)
}
}
@@ -27,4 +27,11 @@ interface ILocationGrabber {
fun locationManager(): LocationState
fun locationFlow(): StateFlow<LocationState.LocationResult>
/**
* A geohash the user picked on the map (via [GeohashLocationPickerDialog]), which
* overrides the live GPS location at build time. Null means "use my current GPS
* location" — the default behavior. Implementers back this with a Compose state.
*/
var pickedGeoHash: String?
}
@@ -82,6 +82,7 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal
import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions
import com.vitorpamplona.quartz.nip01Core.tags.geohash.geohash
import com.vitorpamplona.quartz.nip01Core.tags.geohash.getGeoHash
import com.vitorpamplona.quartz.nip01Core.tags.geohash.hasGeohashes
import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags
import com.vitorpamplona.quartz.nip01Core.tags.people.PTag
@@ -242,6 +243,7 @@ open class CommentPostViewModel :
// GeoHash
var wantsToAddGeoHash by mutableStateOf(false)
override var pickedGeoHash by mutableStateOf<String?>(null)
var location: StateFlow<LocationState.LocationResult>? = null
// ZapRaiser
@@ -510,6 +512,7 @@ open class CommentPostViewModel :
replyingTo?.let { observeCommunityRules(it) }
wantsToAddGeoHash = draftEvent.hasGeohashes()
pickedGeoHash = draftEvent.getGeoHash()
notifying = draftEvent.rootAuthorKeys().mapNotNull { LocalCache.checkGetOrCreateUser(it) } +
draftEvent.replyAuthorKeys().mapNotNull { LocalCache.checkGetOrCreateUser(it) }
@@ -641,7 +644,7 @@ open class CommentPostViewModel :
)
tagger.run()
val geoHash = (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString()
val geoHash = (if (wantsToAddGeoHash) pickedGeoHash else null) ?: (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString()
val emojis = account.emoji.findEmojiTags(tagger.message)
val urls = findURLs(tagger.message)
@@ -867,6 +870,7 @@ open class CommentPostViewModel :
wantsToMarkAsSensitive = false
contentWarningDescription = ""
wantsToAddGeoHash = false
pickedGeoHash = null
wantsSecretEmoji = false
wantsAnonymousPost = false
anonymousSignerCache = null
@@ -72,7 +72,7 @@ import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePick
import com.vitorpamplona.amethyst.ui.note.creators.invoice.AddLnInvoiceButton
import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest
import com.vitorpamplona.amethyst.ui.note.creators.location.AddGeoHashButton
import com.vitorpamplona.amethyst.ui.note.creators.location.LocationAsHash
import com.vitorpamplona.amethyst.ui.note.creators.location.GeoHashPostSection
import com.vitorpamplona.amethyst.ui.note.creators.messagefield.MessageField
import com.vitorpamplona.amethyst.ui.note.creators.notify.Notifying
import com.vitorpamplona.amethyst.ui.note.creators.pow.PowOverrideButton
@@ -330,7 +330,7 @@ private fun GenericCommentPostBody(
verticalAlignment = CenterVertically,
modifier = Modifier.padding(vertical = Size10dp, horizontal = Size10dp),
) {
LocationAsHash(postViewModel)
GeoHashPostSection(postViewModel)
}
}
@@ -246,6 +246,7 @@ class ChatNewMessageViewModel :
// GeoHash
var wantsToAddGeoHash by mutableStateOf(false)
override var pickedGeoHash by mutableStateOf<String?>(null)
var location: StateFlow<LocationState.LocationResult>? = null
// ZapRaiser
@@ -370,6 +371,7 @@ class ChatNewMessageViewModel :
val geohash = draftEvent.getGeoHash()
wantsToAddGeoHash = geohash != null
pickedGeoHash = geohash
val zapraiser = draftEvent.zapraiserAmount()
wantsZapraiser = zapraiser != null
@@ -579,7 +581,7 @@ class ChatNewMessageViewModel :
val urls = findURLs(messageText)
val usedAttachments = iMetaAttachments.filterIsIn(urls.toSet())
val emojis = accountViewModel.account.emoji.findEmojiTags(messageText)
val geoHash = if (wantsToAddGeoHash) (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString() else null
val geoHash = if (wantsToAddGeoHash) (pickedGeoHash ?: (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString()) else null
val message = messageText
val contentWarningReason = if (wantsToMarkAsSensitive) contentWarningDescription else null
@@ -649,6 +651,7 @@ class ChatNewMessageViewModel :
wantsToMarkAsSensitive = false
contentWarningDescription = ""
wantsToAddGeoHash = false
pickedGeoHash = null
wantsSecretEmoji = false
forwardZapTo.value = SplitBuilder()
@@ -100,7 +100,7 @@ import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePick
import com.vitorpamplona.amethyst.ui.note.creators.invoice.AddLnInvoiceButton
import com.vitorpamplona.amethyst.ui.note.creators.invoice.NewPostInvoiceRequest
import com.vitorpamplona.amethyst.ui.note.creators.location.AddGeoHashButton
import com.vitorpamplona.amethyst.ui.note.creators.location.LocationAsHash
import com.vitorpamplona.amethyst.ui.note.creators.location.GeoHashPostSection
import com.vitorpamplona.amethyst.ui.note.creators.messagefield.IMessageField
import com.vitorpamplona.amethyst.ui.note.creators.messagefield.MessageField
import com.vitorpamplona.amethyst.ui.note.creators.previews.PreviewUrl
@@ -250,7 +250,7 @@ fun GroupDMScreenContent(
}
if (postViewModel.wantsToAddGeoHash) {
LocationAsHash(postViewModel)
GeoHashPostSection(postViewModel)
}
if (postViewModel.wantsForwardZapTo) {
@@ -193,6 +193,7 @@ open class ChannelNewMessageViewModel :
// GeoHash
var wantsToAddGeoHash by mutableStateOf(false)
override var pickedGeoHash by mutableStateOf<String?>(null)
var location: StateFlow<LocationState.LocationResult>? = null
// Geohash location chat (Bitchat interop): messages are signed with an anonymous per-cell
@@ -299,6 +300,7 @@ open class ChannelNewMessageViewModel :
val geohash = draftEvent.getGeoHash()
wantsToAddGeoHash = geohash != null
pickedGeoHash = geohash
val zapraiser = draftEvent.zapraiserAmount()
wantsZapraiser = zapraiser != null
@@ -507,7 +509,7 @@ open class ChannelNewMessageViewModel :
val emojis = accountViewModel.account.emoji.findEmojiTags(messageText)
val channelRelays = channel.relays()
val geoHash = if (wantsToAddGeoHash) (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString() else null
val geoHash = if (wantsToAddGeoHash) (pickedGeoHash ?: (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString()) else null
val contentWarningReason = if (wantsToMarkAsSensitive) contentWarningDescription else null
val localExpirationDate = if (wantsExpirationDate) expirationDate else null
@@ -731,6 +733,7 @@ open class ChannelNewMessageViewModel :
wantsToMarkAsSensitive = false
contentWarningDescription = ""
wantsToAddGeoHash = false
pickedGeoHash = null
forwardZapTo = SplitBuilder()
forwardZapToEditting.clearText()
@@ -106,7 +106,7 @@ import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePick
import com.vitorpamplona.amethyst.ui.note.creators.invoice.AddLnInvoiceButton
import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest
import com.vitorpamplona.amethyst.ui.note.creators.location.AddGeoHashButton
import com.vitorpamplona.amethyst.ui.note.creators.location.LocationAsHash
import com.vitorpamplona.amethyst.ui.note.creators.location.GeoHashPostSection
import com.vitorpamplona.amethyst.ui.note.creators.secretEmoji.AddSecretEmojiButton
import com.vitorpamplona.amethyst.ui.note.creators.secretEmoji.SecretEmojiRequest
import com.vitorpamplona.amethyst.ui.note.creators.uploads.ImageVideoDescription
@@ -442,7 +442,7 @@ private fun MarkdownPostScreenBody(
verticalAlignment = CenterVertically,
modifier = Modifier.padding(vertical = Size10dp, horizontal = Size10dp),
) {
LocationAsHash(postViewModel) {
GeoHashPostSection(postViewModel) {
SettingsRow(
R.string.geohash_exclusive,
R.string.geohash_exclusive_explainer,
@@ -205,6 +205,7 @@ class LongFormPostViewModel :
// GeoHash
var wantsToAddGeoHash by mutableStateOf(false)
override var pickedGeoHash by mutableStateOf<String?>(null)
var location: StateFlow<LocationState.LocationResult>? = null
var wantsExclusiveGeoPost by mutableStateOf(false)
@@ -328,6 +329,7 @@ class LongFormPostViewModel :
val geohash = draftEvent.getGeoHash()
wantsToAddGeoHash = geohash != null
pickedGeoHash = geohash
if (geohash != null) {
wantsExclusiveGeoPost = draftEvent.kind == CommentEvent.KIND
}
@@ -411,7 +413,7 @@ class LongFormPostViewModel :
val zapReceiver = if (wantsForwardZapTo) forwardZapTo.value.toZapSplitSetup() else null
val geoHash = if (wantsToAddGeoHash) (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString() else null
val geoHash = if (wantsToAddGeoHash) (pickedGeoHash ?: (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString()) else null
val localZapRaiserAmount = if (wantsZapRaiser) zapRaiserAmount.value else null
val emojis = account.emoji.findEmojiTags(tagger.message)
@@ -631,6 +633,7 @@ class LongFormPostViewModel :
wantsToMarkAsSensitive = false
contentWarningDescription = ""
wantsToAddGeoHash = false
pickedGeoHash = null
wantsExclusiveGeoPost = false
wantsSecretEmoji = false
@@ -65,7 +65,7 @@ import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePick
import com.vitorpamplona.amethyst.ui.note.creators.invoice.AddLnInvoiceButton
import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest
import com.vitorpamplona.amethyst.ui.note.creators.location.AddGeoHashButton
import com.vitorpamplona.amethyst.ui.note.creators.location.LocationAsHash
import com.vitorpamplona.amethyst.ui.note.creators.location.GeoHashPostSection
import com.vitorpamplona.amethyst.ui.note.creators.messagefield.MessageField
import com.vitorpamplona.amethyst.ui.note.creators.previews.DisplayPreviews
import com.vitorpamplona.amethyst.ui.note.creators.secretEmoji.AddSecretEmojiButton
@@ -250,7 +250,7 @@ private fun NewProductBody(
verticalAlignment = CenterVertically,
modifier = Modifier.padding(vertical = Size10dp, horizontal = Size10dp),
) {
LocationAsHash(postViewModel)
GeoHashPostSection(postViewModel)
}
}
@@ -185,6 +185,7 @@ open class NewProductViewModel :
// GeoHash
var wantsToAddGeoHash by mutableStateOf(false)
override var pickedGeoHash by mutableStateOf<String?>(null)
var location: StateFlow<LocationState.LocationResult>? = null
// ZapRaiser
@@ -284,6 +285,7 @@ open class NewProductViewModel :
val geohash = draftEvent.getGeoHash()
wantsToAddGeoHash = geohash != null
pickedGeoHash = geohash
val zapraiser = draftEvent.zapraiserAmount()
wantsZapraiser = zapraiser != null
@@ -353,7 +355,7 @@ open class NewProductViewModel :
val urls = findURLs(tagger.message)
val usedAttachments = iMetaDescription.filterIsIn(urls.toSet()) + productImages.map { it.toIMeta() }
val geoHash = if (wantsToAddGeoHash) (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString() else null
val geoHash = if (wantsToAddGeoHash) (pickedGeoHash ?: (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString()) else null
val zapReceiver = if (wantsForwardZapTo) forwardZapTo.value.toZapSplitSetup() else null
val localZapRaiserAmount = if (wantsZapraiser) zapRaiserAmount.value else null
@@ -484,6 +486,7 @@ open class NewProductViewModel :
wantsToMarkAsSensitive = false
contentWarningDescription = ""
wantsToAddGeoHash = false
pickedGeoHash = null
wantsSecretEmoji = false
forwardZapTo.value = SplitBuilder()
@@ -107,9 +107,7 @@ import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePick
import com.vitorpamplona.amethyst.ui.note.creators.invoice.AddLnInvoiceButton
import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest
import com.vitorpamplona.amethyst.ui.note.creators.location.AddGeoHashButton
import com.vitorpamplona.amethyst.ui.note.creators.location.DisplayLocationInTitle
import com.vitorpamplona.amethyst.ui.note.creators.location.GeohashLocationPickerDialog
import com.vitorpamplona.amethyst.ui.note.creators.location.LocationAsHash
import com.vitorpamplona.amethyst.ui.note.creators.location.GeoHashPostSection
import com.vitorpamplona.amethyst.ui.note.creators.messagefield.MessageField
import com.vitorpamplona.amethyst.ui.note.creators.notify.Notifying
import com.vitorpamplona.amethyst.ui.note.creators.polls.PollOptionsField
@@ -530,7 +528,14 @@ private fun NewPostScreenBody(
}
if (postViewModel.wantsToAddGeoHash) {
GeoHashPostSection(postViewModel)
GeoHashPostSection(postViewModel) {
SettingsRow(
R.string.geohash_exclusive,
R.string.geohash_exclusive_explainer,
) {
Switch(postViewModel.wantsExclusiveGeoPost, onCheckedChange = { postViewModel.wantsExclusiveGeoPost = it })
}
}
}
if (postViewModel.wantsForwardZapTo) {
@@ -872,85 +877,6 @@ private fun BottomRowActions(
}
}
/**
* The composer's location section. Defaults to the device GPS flow ([LocationAsHash]),
* but a "pick on map" action opens the shared [GeohashLocationPickerDialog] and stores
* the chosen geohash in [ShortNotePostViewModel.pickedGeoHash], which then overrides GPS
* at build time. Picking a place also skips the GPS permission prompt.
*/
@Composable
private fun GeoHashPostSection(postViewModel: ShortNotePostViewModel) {
var showPicker by remember { mutableStateOf(false) }
val picked = postViewModel.pickedGeoHash
Column(
modifier = Modifier.fillMaxWidth().padding(vertical = Size10dp, horizontal = Size10dp),
) {
if (picked != null) {
// A map-picked place: show it, and let the user clear back to GPS.
Row(verticalAlignment = CenterVertically, modifier = Modifier.fillMaxWidth()) {
Icon(
symbol = MaterialSymbols.LocationOn,
contentDescription = null,
modifier = Modifier.size(20.dp),
tint = MaterialTheme.colorScheme.primary,
)
Text(
text = stringRes(R.string.geohash_title),
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.W500,
modifier = Modifier.padding(start = 10.dp),
)
DisplayLocationInTitle(geohash = picked)
Spacer(modifier = Modifier.weight(1f))
IconButton(onClick = { postViewModel.pickedGeoHash = null }) {
Icon(
symbol = MaterialSymbols.Close,
contentDescription = stringRes(R.string.remove_location),
modifier = Modifier.size(20.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
HorizontalDivider()
SettingsRow(R.string.geohash_exclusive, R.string.geohash_exclusive_explainer) {
Switch(postViewModel.wantsExclusiveGeoPost, onCheckedChange = { postViewModel.wantsExclusiveGeoPost = it })
}
} else {
// GPS mode (unchanged): current device location + the exclusive-post switch.
LocationAsHash(postViewModel) {
SettingsRow(R.string.geohash_exclusive, R.string.geohash_exclusive_explainer) {
Switch(postViewModel.wantsExclusiveGeoPost, onCheckedChange = { postViewModel.wantsExclusiveGeoPost = it })
}
}
}
TextButton(onClick = { showPicker = true }, modifier = Modifier.padding(top = 4.dp)) {
Icon(
symbol = MaterialSymbols.LocationOn,
contentDescription = null,
modifier = Modifier.size(18.dp),
tint = MaterialTheme.colorScheme.primary,
)
Text(
text = stringRes(if (picked != null) R.string.location_change_place else R.string.location_pick_on_map),
modifier = Modifier.padding(start = 6.dp),
)
}
}
if (showPicker) {
GeohashLocationPickerDialog(
initialGeohash = picked,
onDismiss = { showPicker = false },
onConfirm = { cell ->
postViewModel.pickedGeoHash = cell
showPicker = false
},
)
}
}
@SuppressLint("ViewModelConstructorInComposable")
@Preview
@Composable
@@ -330,11 +330,7 @@ open class ShortNotePostViewModel :
var wantsToAddGeoHash by mutableStateOf(false)
var location: StateFlow<LocationState.LocationResult>? = null
/**
* A geohash the user picked on the map, which overrides the live GPS location at
* build time. Null means "use my current GPS location" (the default behavior).
*/
var pickedGeoHash by mutableStateOf<String?>(null)
override var pickedGeoHash by mutableStateOf<String?>(null)
var wantsExclusiveGeoPost by mutableStateOf(false)
// ZapRaiser
@@ -178,6 +178,7 @@ open class NestNewMessageViewModel :
// GeoHash
var wantsToAddGeoHash by mutableStateOf(false)
override var pickedGeoHash by mutableStateOf<String?>(null)
var location: StateFlow<LocationState.LocationResult>? = null
// ZapRaiser
@@ -272,6 +273,7 @@ open class NestNewMessageViewModel :
val geohash = draftEvent.getGeoHash()
wantsToAddGeoHash = geohash != null
pickedGeoHash = geohash
val zapraiser = draftEvent.zapraiserAmount()
wantsZapraiser = zapraiser != null
@@ -427,7 +429,7 @@ open class NestNewMessageViewModel :
val usedAttachments = iMetaAttachments.filterIsIn(urls.toSet())
val emojis = accountViewModel.account.emoji.findEmojiTags(messageText)
val geoHash = if (wantsToAddGeoHash) (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString() else null
val geoHash = if (wantsToAddGeoHash) (pickedGeoHash ?: (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString()) else null
val contentWarningReason = if (wantsToMarkAsSensitive) contentWarningDescription else null
val localExpirationDate = if (wantsExpirationDate) expirationDate else null
@@ -482,6 +484,7 @@ open class NestNewMessageViewModel :
wantsToMarkAsSensitive = false
contentWarningDescription = ""
wantsToAddGeoHash = false
pickedGeoHash = null
forwardZapTo = SplitBuilder()
forwardZapToEditting.clearText()
@@ -76,7 +76,7 @@ import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePick
import com.vitorpamplona.amethyst.ui.note.creators.invoice.AddLnInvoiceButton
import com.vitorpamplona.amethyst.ui.note.creators.invoice.NewPostInvoiceRequest
import com.vitorpamplona.amethyst.ui.note.creators.location.AddGeoHashButton
import com.vitorpamplona.amethyst.ui.note.creators.location.LocationAsHash
import com.vitorpamplona.amethyst.ui.note.creators.location.GeoHashPostSection
import com.vitorpamplona.amethyst.ui.note.creators.previews.DisplayPreviews
import com.vitorpamplona.amethyst.ui.note.creators.secretEmoji.AddSecretEmojiButton
import com.vitorpamplona.amethyst.ui.note.creators.secretEmoji.SecretEmojiRequest
@@ -233,7 +233,7 @@ fun PublicMessageScreenContent(
}
if (postViewModel.wantsToAddGeoHash) {
LocationAsHash(postViewModel)
GeoHashPostSection(postViewModel)
}
if (postViewModel.wantsForwardZapTo) {
@@ -197,6 +197,7 @@ class NewPublicMessageViewModel :
// GeoHash
var wantsToAddGeoHash by mutableStateOf(false)
override var pickedGeoHash by mutableStateOf<String?>(null)
var location: StateFlow<LocationState.LocationResult>? = null
// ZapRaiser
@@ -300,6 +301,7 @@ class NewPublicMessageViewModel :
val geohash = draftEvent.getGeoHash()
wantsToAddGeoHash = geohash != null
pickedGeoHash = geohash
val zapraiser = draftEvent.zapraiserAmount()
wantsZapraiser = zapraiser != null
@@ -388,7 +390,7 @@ class NewPublicMessageViewModel :
val zapReceiver = if (wantsForwardZapTo) forwardZapTo.value.toZapSplitSetup() else null
val geoHash = (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString()
val geoHash = (if (wantsToAddGeoHash) pickedGeoHash else null) ?: (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString()
val localZapRaiserAmount = if (wantsZapraiser) zapRaiserAmount.value else null
val emojis = account.emoji.findEmojiTags(tagger.message)
@@ -528,6 +530,7 @@ class NewPublicMessageViewModel :
wantsToMarkAsSensitive = false
contentWarningDescription = ""
wantsToAddGeoHash = false
pickedGeoHash = null
wantsSecretEmoji = false
forwardZapTo.value = SplitBuilder()