mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-10 00:16:59 +00:00
Adds expirations in all new post screens.
Adds expirations in the feed and chats.
This commit is contained in:
@@ -30,6 +30,10 @@ import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Timer
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Text
|
||||
@@ -47,6 +51,7 @@ import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.compositeOver
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.R
|
||||
@@ -201,6 +206,7 @@ import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent
|
||||
import com.vitorpamplona.quartz.nip35Torrents.TorrentCommentEvent
|
||||
import com.vitorpamplona.quartz.nip35Torrents.TorrentEvent
|
||||
import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent
|
||||
import com.vitorpamplona.quartz.nip40Expiration.expiration
|
||||
import com.vitorpamplona.quartz.nip50Search.SearchRelayListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.PinListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.followList.FollowListEvent
|
||||
@@ -1344,6 +1350,26 @@ fun SecondUserInfoRow(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DisplayExpiration(expirationDate: Long) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Timer,
|
||||
contentDescription = stringRes(R.string.expiration_date_label),
|
||||
modifier = Modifier.size(15.dp),
|
||||
tint = MaterialTheme.colorScheme.placeholderText,
|
||||
)
|
||||
val context = LocalContext.current
|
||||
Text(
|
||||
text = timeAheadNoDot(expirationDate, context),
|
||||
color = MaterialTheme.colorScheme.placeholderText,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DisplayOtsIfInOriginal(
|
||||
note: Note,
|
||||
@@ -1440,6 +1466,8 @@ fun FirstUserInfoRow(
|
||||
DisplayDraft()
|
||||
}
|
||||
|
||||
Expiration(baseNote)
|
||||
|
||||
TimeAgo(baseNote)
|
||||
|
||||
if (moreOptions == null) {
|
||||
@@ -1450,6 +1478,17 @@ fun FirstUserInfoRow(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Expiration(note: Note) {
|
||||
val event = note.event
|
||||
if (event != null) {
|
||||
val expires = remember(event) { event.expiration() }
|
||||
if (expires != null) {
|
||||
DisplayExpiration(expires)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CheckAndDisplayEditStatus(editState: State<GenericLoadable<EditState>>) {
|
||||
if (editState.value is GenericLoadable.Loaded) {
|
||||
|
||||
+1
-2
@@ -58,7 +58,6 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.ui.note.timeAheadNoDot
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.ShortNotePostViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||
@@ -69,7 +68,7 @@ import java.time.ZoneOffset
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ExpirationDatePicker(model: ShortNotePostViewModel) {
|
||||
fun ExpirationDatePicker(model: IExpiration) {
|
||||
var showDatePicker by remember { mutableStateOf(false) }
|
||||
var showTimePicker by remember { mutableStateOf(false) }
|
||||
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.expiration
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
|
||||
@Stable
|
||||
interface IExpiration {
|
||||
var expirationDate: Long
|
||||
}
|
||||
+25
-1
@@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.note.nip22Comments
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableLongStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
@@ -48,6 +49,7 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMediaProcessing
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.draftTags.DraftTagState
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.EmojiSuggestionState
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.IExpiration
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.location.ILocationGrabber
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.messagefield.IMessageField
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.previews.PreviewState
|
||||
@@ -84,6 +86,7 @@ import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarning
|
||||
import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarningReason
|
||||
import com.vitorpamplona.quartz.nip36SensitiveContent.isSensitive
|
||||
import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent
|
||||
import com.vitorpamplona.quartz.nip40Expiration.expiration
|
||||
import com.vitorpamplona.quartz.nip57Zaps.splits.zapSplits
|
||||
import com.vitorpamplona.quartz.nip57Zaps.zapraiser.zapraiser
|
||||
import com.vitorpamplona.quartz.nip57Zaps.zapraiser.zapraiserAmount
|
||||
@@ -101,6 +104,7 @@ import com.vitorpamplona.quartz.nip94FileMetadata.mimeType
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.originalHash
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.sensitiveContent
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.size
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
@@ -113,7 +117,8 @@ open class CommentPostViewModel :
|
||||
ILocationGrabber,
|
||||
IMessageField,
|
||||
IZapField,
|
||||
IZapRaiser {
|
||||
IZapRaiser,
|
||||
IExpiration {
|
||||
val draftTag = DraftTagState()
|
||||
|
||||
init {
|
||||
@@ -169,6 +174,10 @@ open class CommentPostViewModel :
|
||||
var wantsToMarkAsSensitive by mutableStateOf(false)
|
||||
var contentWarningDescription by mutableStateOf("")
|
||||
|
||||
// Expiration Date (NIP-40)
|
||||
var wantsExpirationDate by mutableStateOf(false)
|
||||
override var expirationDate by mutableLongStateOf(TimeUtils.oneDayAhead())
|
||||
|
||||
// GeoHash
|
||||
var wantsToAddGeoHash by mutableStateOf(false)
|
||||
var location: StateFlow<LocationState.LocationResult>? = null
|
||||
@@ -274,6 +283,10 @@ open class CommentPostViewModel :
|
||||
wantsToMarkAsSensitive = draftEvent.isSensitive()
|
||||
contentWarningDescription = draftEvent.contentWarningReason() ?: ""
|
||||
|
||||
val draftExpiration = draftEvent.expiration()
|
||||
wantsExpirationDate = draftExpiration != null
|
||||
expirationDate = draftExpiration ?: TimeUtils.oneDayAhead()
|
||||
|
||||
val zapraiser = draftEvent.zapraiserAmount()
|
||||
wantsZapraiser = zapraiser != null
|
||||
zapRaiserAmount.value = null
|
||||
@@ -363,6 +376,7 @@ open class CommentPostViewModel :
|
||||
val zapReceiver = if (wantsForwardZapTo) forwardZapTo.value.toZapSplitSetup() else null
|
||||
val localZapRaiserAmount = if (wantsZapraiser) zapRaiserAmount.value else null
|
||||
val contentWarningReason = if (wantsToMarkAsSensitive) contentWarningDescription else null
|
||||
val localExpirationDate = if (wantsExpirationDate) expirationDate else null
|
||||
|
||||
val replyingTo = replyingTo
|
||||
val replyingToEvent = replyingTo?.event
|
||||
@@ -399,6 +413,7 @@ open class CommentPostViewModel :
|
||||
localZapRaiserAmount?.let { zapraiser(it) }
|
||||
zapReceiver?.let { zapSplits(it) }
|
||||
contentWarningReason?.let { contentWarning(it) }
|
||||
localExpirationDate?.let { expiration(it) }
|
||||
|
||||
emojis(emojis)
|
||||
imetas(usedAttachments)
|
||||
@@ -419,6 +434,7 @@ open class CommentPostViewModel :
|
||||
localZapRaiserAmount?.let { zapraiser(it) }
|
||||
zapReceiver?.let { zapSplits(it) }
|
||||
contentWarningReason?.let { contentWarning(it) }
|
||||
localExpirationDate?.let { expiration(it) }
|
||||
|
||||
emojis(emojis)
|
||||
imetas(usedAttachments)
|
||||
@@ -703,6 +719,14 @@ open class CommentPostViewModel :
|
||||
draftTag.newVersion()
|
||||
}
|
||||
|
||||
fun toggleExpirationDate() {
|
||||
wantsExpirationDate = !wantsExpirationDate
|
||||
if (wantsExpirationDate) {
|
||||
expirationDate = TimeUtils.oneDayAhead()
|
||||
}
|
||||
draftTag.newVersion()
|
||||
}
|
||||
|
||||
override fun locationFlow(): StateFlow<LocationState.LocationResult> {
|
||||
if (location == null) {
|
||||
location = locationManager().geohashStateFlow
|
||||
|
||||
+15
@@ -61,6 +61,8 @@ import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.ContentSensiti
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.MarkAsSensitiveButton
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.ShowEmojiSuggestionList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDateButton
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
|
||||
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
|
||||
@@ -262,6 +264,15 @@ private fun GenericCommentPostBody(
|
||||
}
|
||||
}
|
||||
|
||||
if (postViewModel.wantsExpirationDate) {
|
||||
Row(
|
||||
verticalAlignment = CenterVertically,
|
||||
modifier = Modifier.padding(vertical = Size5dp, horizontal = Size10dp),
|
||||
) {
|
||||
ExpirationDatePicker(postViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
if (postViewModel.wantsToAddGeoHash) {
|
||||
Row(
|
||||
verticalAlignment = CenterVertically,
|
||||
@@ -420,6 +431,10 @@ private fun BottomRowActions(postViewModel: CommentPostViewModel) {
|
||||
postViewModel.toggleMarkAsSensitive()
|
||||
}
|
||||
|
||||
ExpirationDateButton(postViewModel.wantsExpirationDate) {
|
||||
postViewModel.toggleExpirationDate()
|
||||
}
|
||||
|
||||
AddGeoHashButton(postViewModel.wantsToAddGeoHash) {
|
||||
postViewModel.wantsToAddGeoHash = !postViewModel.wantsToAddGeoHash
|
||||
}
|
||||
|
||||
+1
@@ -204,6 +204,7 @@ fun NormalChatNote(
|
||||
) {
|
||||
IncognitoBadge(note)
|
||||
ChatTimeAgo(note)
|
||||
ChatExpiration(note)
|
||||
RelayBadgesHorizontal(note, accountViewModel, nav = nav)
|
||||
|
||||
Spacer(modifier = DoubleHorzSpacer)
|
||||
|
||||
+46
@@ -20,16 +20,29 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Timer
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.note.timeAgoShort
|
||||
import com.vitorpamplona.amethyst.ui.note.timeAheadNoDot
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.Font12SP
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||
import com.vitorpamplona.quartz.nip40Expiration.expiration
|
||||
|
||||
@Composable
|
||||
fun ChatTimeAgo(baseNote: Note) {
|
||||
@@ -43,3 +56,36 @@ fun ChatTimeAgo(baseNote: Note) {
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ChatExpiration(note: Note) {
|
||||
val event = note.event
|
||||
if (event != null) {
|
||||
val expires = remember(event) { event.expiration() }
|
||||
if (expires != null) {
|
||||
ChatDisplayExpiration(expires)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ChatDisplayExpiration(expirationDate: Long) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Timer,
|
||||
contentDescription = stringRes(R.string.expiration_date_label),
|
||||
modifier = Modifier.size(12.dp),
|
||||
tint = MaterialTheme.colorScheme.placeholderText,
|
||||
)
|
||||
val context = LocalContext.current
|
||||
Text(
|
||||
text = timeAheadNoDot(expirationDate, context),
|
||||
color = MaterialTheme.colorScheme.placeholderText,
|
||||
fontSize = Font12SP,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+26
-12
@@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableLongStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
@@ -42,6 +43,7 @@ import com.vitorpamplona.amethyst.ui.actions.NewMessageTagger
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.draftTags.DraftTagState
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.EmojiSuggestionState
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.IExpiration
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.location.ILocationGrabber
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.messagefield.IMessageField
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.previews.PreviewState
|
||||
@@ -104,7 +106,8 @@ class ChatNewMessageViewModel :
|
||||
ILocationGrabber,
|
||||
IMessageField,
|
||||
IZapField,
|
||||
IZapRaiser {
|
||||
IZapRaiser,
|
||||
IExpiration {
|
||||
val draftTag = DraftTagState()
|
||||
|
||||
lateinit var accountViewModel: AccountViewModel
|
||||
@@ -163,6 +166,10 @@ class ChatNewMessageViewModel :
|
||||
var wantsToMarkAsSensitive by mutableStateOf(false)
|
||||
var contentWarningDescription by mutableStateOf("")
|
||||
|
||||
// Expiration Date (NIP-40)
|
||||
var wantsExpirationDate by mutableStateOf(false)
|
||||
override var expirationDate by mutableLongStateOf(TimeUtils.oneDayAhead())
|
||||
|
||||
// GeoHash
|
||||
var wantsToAddGeoHash by mutableStateOf(false)
|
||||
var location: StateFlow<LocationState.LocationResult>? = null
|
||||
@@ -172,8 +179,6 @@ class ChatNewMessageViewModel :
|
||||
var wantsZapraiser by mutableStateOf(false)
|
||||
override var zapRaiserAmount = mutableStateOf<Long?>(null)
|
||||
|
||||
var expirationDays by mutableStateOf<Int?>(null)
|
||||
|
||||
// NIP17 Wrapped DMs / Group messages
|
||||
var nip17 by mutableStateOf(false)
|
||||
|
||||
@@ -274,7 +279,8 @@ class ChatNewMessageViewModel :
|
||||
}
|
||||
|
||||
fun loadExpiration(expirationDays: Int) {
|
||||
this.expirationDays = expirationDays
|
||||
this.wantsExpirationDate = true
|
||||
this.expirationDate = TimeUtils.now() + expirationDays * 86400L
|
||||
}
|
||||
|
||||
private fun loadFromDraft(draft: Note) {
|
||||
@@ -296,6 +302,10 @@ class ChatNewMessageViewModel :
|
||||
wantsToMarkAsSensitive = draftEvent.isSensitive()
|
||||
contentWarningDescription = draftEvent.contentWarningReason() ?: ""
|
||||
|
||||
val draftExpiration = draftEvent.expiration()
|
||||
wantsExpirationDate = draftExpiration != null
|
||||
expirationDate = draftExpiration ?: TimeUtils.oneDayAhead()
|
||||
|
||||
val geohash = draftEvent.getGeoHash()
|
||||
wantsToAddGeoHash = geohash != null
|
||||
|
||||
@@ -348,8 +358,6 @@ class ChatNewMessageViewModel :
|
||||
}
|
||||
urlPreviews.update(message)
|
||||
|
||||
expirationDays = draftEvent.expiration()?.let { (it / 86_400).toInt() }
|
||||
|
||||
iMetaAttachments.addAll(draftEvent.imetas())
|
||||
|
||||
requiresNIP17 = draftEvent is NIP17Group
|
||||
@@ -444,11 +452,10 @@ class ChatNewMessageViewModel :
|
||||
val message = message.text
|
||||
|
||||
val contentWarningReason = if (wantsToMarkAsSensitive) contentWarningDescription else null
|
||||
val localExpirationDate = if (wantsExpirationDate) expirationDate else null
|
||||
val localZapRaiserAmount = if (wantsZapraiser) zapRaiserAmount.value else null
|
||||
val zapReceiver = if (wantsForwardZapTo) forwardZapTo.value.toZapSplitSetup() else null
|
||||
|
||||
val expiration = expirationDays?.let { TimeUtils.now() + it.toLong() * 86_400 }
|
||||
|
||||
if (nip17 || room.users.size > 1 || replyTo.value?.event is NIP17Group) {
|
||||
val replyHint = replyTo.value?.toEventHint<BaseDMGroupEvent>()
|
||||
|
||||
@@ -463,7 +470,7 @@ class ChatNewMessageViewModel :
|
||||
localZapRaiserAmount?.let { zapraiser(it) }
|
||||
zapReceiver?.let { zapSplits(it) }
|
||||
contentWarningReason?.let { contentWarning(it) }
|
||||
expiration?.let { expiration(it) }
|
||||
localExpirationDate?.let { expiration(it) }
|
||||
|
||||
emojis(emojis)
|
||||
imetas(usedAttachments)
|
||||
@@ -478,7 +485,7 @@ class ChatNewMessageViewModel :
|
||||
localZapRaiserAmount?.let { zapraiser(it) }
|
||||
zapReceiver?.let { zapSplits(it) }
|
||||
contentWarningReason?.let { contentWarning(it) }
|
||||
expiration?.let { expiration(it) }
|
||||
localExpirationDate?.let { expiration(it) }
|
||||
|
||||
emojis(emojis)
|
||||
imetas(usedAttachments)
|
||||
@@ -501,7 +508,7 @@ class ChatNewMessageViewModel :
|
||||
replyingTo = replyTo.value?.toEventHint<PrivateDmEvent>(),
|
||||
signer = accountViewModel.account.signer,
|
||||
) {
|
||||
expiration?.let { expiration(it) }
|
||||
localExpirationDate?.let { expiration(it) }
|
||||
}
|
||||
|
||||
if (draftTag != null) {
|
||||
@@ -533,7 +540,6 @@ class ChatNewMessageViewModel :
|
||||
subject = TextFieldValue("")
|
||||
|
||||
replyTo.value = null
|
||||
expirationDays = null
|
||||
|
||||
wantsInvoice = false
|
||||
wantsZapraiser = false
|
||||
@@ -742,5 +748,13 @@ class ChatNewMessageViewModel :
|
||||
draftTag.newVersion()
|
||||
}
|
||||
|
||||
fun toggleExpirationDate() {
|
||||
wantsExpirationDate = !wantsExpirationDate
|
||||
if (wantsExpirationDate) {
|
||||
expirationDate = TimeUtils.oneDayAhead()
|
||||
}
|
||||
draftTag.newVersion()
|
||||
}
|
||||
|
||||
override fun locationManager(): LocationState = Amethyst.instance.locationManager
|
||||
}
|
||||
|
||||
+10
@@ -97,6 +97,8 @@ import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.ContentSensiti
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.MarkAsSensitiveButton
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.ShowEmojiSuggestionList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDateButton
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
|
||||
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
|
||||
@@ -244,6 +246,10 @@ fun GroupDMScreenContent(
|
||||
)
|
||||
}
|
||||
|
||||
if (postViewModel.wantsExpirationDate) {
|
||||
ExpirationDatePicker(postViewModel)
|
||||
}
|
||||
|
||||
if (postViewModel.wantsToAddGeoHash) {
|
||||
LocationAsHash(postViewModel)
|
||||
}
|
||||
@@ -458,6 +464,10 @@ private fun BottomRowActions(
|
||||
postViewModel.toggleMarkAsSensitive()
|
||||
}
|
||||
|
||||
ExpirationDateButton(postViewModel.wantsExpirationDate) {
|
||||
postViewModel.toggleExpirationDate()
|
||||
}
|
||||
|
||||
AddGeoHashButton(postViewModel.wantsToAddGeoHash) {
|
||||
postViewModel.wantsToAddGeoHash = !postViewModel.wantsToAddGeoHash
|
||||
}
|
||||
|
||||
+9
-12
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send
|
||||
|
||||
import android.R.attr.maxLines
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -33,20 +34,20 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.ui.actions.UrlUserTagTransformation
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
|
||||
import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.ShowEmojiSuggestionList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList
|
||||
import com.vitorpamplona.amethyst.ui.note.timeAheadNoDot
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.upload.RoomChatFileUploadDialog
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.DisplayReplyingToNote
|
||||
@@ -134,10 +135,14 @@ fun PrivateMessageEditFieldRow(
|
||||
)
|
||||
}
|
||||
|
||||
channelScreenModel.expirationDays?.let {
|
||||
if (channelScreenModel.wantsExpirationDate) {
|
||||
Row(Modifier.fillMaxWidth().padding(vertical = 2.dp), horizontalArrangement = Arrangement.Center) {
|
||||
val context = LocalContext.current
|
||||
Text(
|
||||
stringResource(R.string.this_message_will_disappear_in_days, it),
|
||||
stringRes(
|
||||
R.string.this_message_will_disappear_in,
|
||||
timeAheadNoDot(channelScreenModel.expirationDate, context),
|
||||
),
|
||||
fontSize = Font12SP,
|
||||
color = MaterialTheme.colorScheme.placeholderText,
|
||||
maxLines = 1,
|
||||
@@ -207,14 +212,6 @@ fun KeyboardLeadingIcon(
|
||||
onImageChosen = channelScreenModel::pickedMedia,
|
||||
)
|
||||
|
||||
SelectFromFiles(
|
||||
isUploading = channelScreenModel.isUploadingImage,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
modifier = Modifier,
|
||||
) {
|
||||
channelScreenModel.pickedMedia(it)
|
||||
}
|
||||
|
||||
ToggleNip17Button(channelScreenModel, accountViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
+30
-1
@@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.send
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableLongStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
@@ -50,6 +51,7 @@ import com.vitorpamplona.amethyst.ui.actions.NewMessageTagger
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.draftTags.DraftTagState
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.EmojiSuggestionState
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.IExpiration
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.location.ILocationGrabber
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.SplitBuilder
|
||||
@@ -85,6 +87,7 @@ import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarning
|
||||
import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarningReason
|
||||
import com.vitorpamplona.quartz.nip36SensitiveContent.isSensitive
|
||||
import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent
|
||||
import com.vitorpamplona.quartz.nip40Expiration.expiration
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.chat.notify
|
||||
import com.vitorpamplona.quartz.nip57Zaps.splits.ZapSplitSetup
|
||||
@@ -92,6 +95,7 @@ import com.vitorpamplona.quartz.nip57Zaps.splits.zapSplitSetup
|
||||
import com.vitorpamplona.quartz.nip57Zaps.zapraiser.zapraiserAmount
|
||||
import com.vitorpamplona.quartz.nip92IMeta.imetas
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
@@ -101,7 +105,8 @@ import kotlinx.coroutines.launch
|
||||
@Stable
|
||||
open class ChannelNewMessageViewModel :
|
||||
ViewModel(),
|
||||
ILocationGrabber {
|
||||
ILocationGrabber,
|
||||
IExpiration {
|
||||
val draftTag = DraftTagState()
|
||||
|
||||
init {
|
||||
@@ -149,6 +154,10 @@ open class ChannelNewMessageViewModel :
|
||||
var wantsToMarkAsSensitive by mutableStateOf(false)
|
||||
var contentWarningDescription by mutableStateOf("")
|
||||
|
||||
// Expiration Date (NIP-40)
|
||||
var wantsExpirationDate by mutableStateOf(false)
|
||||
override var expirationDate by mutableLongStateOf(TimeUtils.oneDayAhead())
|
||||
|
||||
// GeoHash
|
||||
var wantsToAddGeoHash by mutableStateOf(false)
|
||||
var location: StateFlow<LocationState.LocationResult>? = null
|
||||
@@ -229,6 +238,10 @@ open class ChannelNewMessageViewModel :
|
||||
wantsToMarkAsSensitive = draftEvent.isSensitive()
|
||||
contentWarningDescription = draftEvent.contentWarningReason() ?: ""
|
||||
|
||||
val draftExpiration = draftEvent.expiration()
|
||||
wantsExpirationDate = draftExpiration != null
|
||||
expirationDate = draftExpiration ?: TimeUtils.oneDayAhead()
|
||||
|
||||
val geohash = draftEvent.getGeoHash()
|
||||
wantsToAddGeoHash = geohash != null
|
||||
|
||||
@@ -388,6 +401,7 @@ open class ChannelNewMessageViewModel :
|
||||
val geoHash = if (wantsToAddGeoHash) (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString() else null
|
||||
|
||||
val contentWarningReason = if (wantsToMarkAsSensitive) contentWarningDescription else null
|
||||
val localExpirationDate = if (wantsExpirationDate) expirationDate else null
|
||||
|
||||
return if (channel is PublicChatChannel) {
|
||||
val replyingToEvent = replyTo.value?.toEventHint<ChannelMessageEvent>()
|
||||
@@ -401,6 +415,7 @@ open class ChannelNewMessageViewModel :
|
||||
references(findURLs(tagger.message))
|
||||
quotes(findNostrUris(tagger.message))
|
||||
contentWarningReason?.let { contentWarning(it) }
|
||||
localExpirationDate?.let { expiration(it) }
|
||||
|
||||
geoHash?.let { geohash(it) }
|
||||
|
||||
@@ -414,6 +429,7 @@ open class ChannelNewMessageViewModel :
|
||||
references(findURLs(tagger.message))
|
||||
quotes(findNostrUris(tagger.message))
|
||||
contentWarningReason?.let { contentWarning(it) }
|
||||
localExpirationDate?.let { expiration(it) }
|
||||
|
||||
geoHash?.let { geohash(it) }
|
||||
|
||||
@@ -426,6 +442,7 @@ open class ChannelNewMessageViewModel :
|
||||
references(findURLs(tagger.message))
|
||||
quotes(findNostrUris(tagger.message))
|
||||
contentWarningReason?.let { contentWarning(it) }
|
||||
localExpirationDate?.let { expiration(it) }
|
||||
|
||||
geoHash?.let { geohash(it) }
|
||||
|
||||
@@ -445,6 +462,7 @@ open class ChannelNewMessageViewModel :
|
||||
references(findURLs(tagger.message))
|
||||
quotes(findNostrUris(tagger.message))
|
||||
contentWarningReason?.let { contentWarning(it) }
|
||||
localExpirationDate?.let { expiration(it) }
|
||||
|
||||
emojis(emojis)
|
||||
imetas(usedAttachments)
|
||||
@@ -457,6 +475,7 @@ open class ChannelNewMessageViewModel :
|
||||
references(findURLs(tagger.message))
|
||||
quotes(findNostrUris(tagger.message))
|
||||
contentWarningReason?.let { contentWarning(it) }
|
||||
localExpirationDate?.let { expiration(it) }
|
||||
|
||||
emojis(emojis)
|
||||
imetas(usedAttachments)
|
||||
@@ -467,6 +486,7 @@ open class ChannelNewMessageViewModel :
|
||||
references(findURLs(tagger.message))
|
||||
quotes(findNostrUris(tagger.message))
|
||||
contentWarningReason?.let { contentWarning(it) }
|
||||
localExpirationDate?.let { expiration(it) }
|
||||
|
||||
emojis(emojis)
|
||||
imetas(usedAttachments)
|
||||
@@ -482,6 +502,7 @@ open class ChannelNewMessageViewModel :
|
||||
references(findURLs(tagger.message))
|
||||
quotes(findNostrUris(tagger.message))
|
||||
contentWarningReason?.let { contentWarning(it) }
|
||||
localExpirationDate?.let { expiration(it) }
|
||||
|
||||
emojis(emojis)
|
||||
imetas(usedAttachments)
|
||||
@@ -663,4 +684,12 @@ open class ChannelNewMessageViewModel :
|
||||
wantsToMarkAsSensitive = !wantsToMarkAsSensitive
|
||||
draftTag.newVersion()
|
||||
}
|
||||
|
||||
fun toggleExpirationDate() {
|
||||
wantsExpirationDate = !wantsExpirationDate
|
||||
if (wantsExpirationDate) {
|
||||
expirationDate = TimeUtils.oneDayAhead()
|
||||
}
|
||||
draftTag.newVersion()
|
||||
}
|
||||
}
|
||||
|
||||
+15
@@ -60,6 +60,8 @@ import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.ContentSensiti
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.MarkAsSensitiveButton
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.ShowEmojiSuggestionList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDateButton
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
|
||||
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
|
||||
@@ -230,6 +232,15 @@ private fun NewProductBody(
|
||||
}
|
||||
}
|
||||
|
||||
if (postViewModel.wantsExpirationDate) {
|
||||
Row(
|
||||
verticalAlignment = CenterVertically,
|
||||
modifier = Modifier.padding(vertical = Size5dp, horizontal = Size10dp),
|
||||
) {
|
||||
ExpirationDatePicker(postViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
if (postViewModel.wantsToAddGeoHash) {
|
||||
Row(
|
||||
verticalAlignment = CenterVertically,
|
||||
@@ -388,6 +399,10 @@ private fun BottomRowActions(postViewModel: NewProductViewModel) {
|
||||
postViewModel.toggleMarkAsSensitive()
|
||||
}
|
||||
|
||||
ExpirationDateButton(postViewModel.wantsExpirationDate) {
|
||||
postViewModel.toggleExpirationDate()
|
||||
}
|
||||
|
||||
AddGeoHashButton(postViewModel.wantsToAddGeoHash) {
|
||||
postViewModel.wantsToAddGeoHash = !postViewModel.wantsToAddGeoHash
|
||||
}
|
||||
|
||||
+24
-1
@@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip99Classifieds
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableLongStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
@@ -48,6 +49,7 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMediaProcessing
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.draftTags.DraftTagState
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.EmojiSuggestionState
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.IExpiration
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.location.ILocationGrabber
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.messagefield.IMessageField
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.previews.PreviewState
|
||||
@@ -79,6 +81,7 @@ import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarning
|
||||
import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarningReason
|
||||
import com.vitorpamplona.quartz.nip36SensitiveContent.isSensitive
|
||||
import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent
|
||||
import com.vitorpamplona.quartz.nip40Expiration.expiration
|
||||
import com.vitorpamplona.quartz.nip57Zaps.splits.zapSplits
|
||||
import com.vitorpamplona.quartz.nip57Zaps.zapraiser.zapraiser
|
||||
import com.vitorpamplona.quartz.nip57Zaps.zapraiser.zapraiserAmount
|
||||
@@ -89,6 +92,7 @@ import com.vitorpamplona.quartz.nip99Classifieds.image
|
||||
import com.vitorpamplona.quartz.nip99Classifieds.tags.ConditionTag
|
||||
import com.vitorpamplona.quartz.nip99Classifieds.tags.PriceTag
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -102,7 +106,8 @@ open class NewProductViewModel :
|
||||
ILocationGrabber,
|
||||
IMessageField,
|
||||
IZapField,
|
||||
IZapRaiser {
|
||||
IZapRaiser,
|
||||
IExpiration {
|
||||
val draftTag = DraftTagState()
|
||||
|
||||
lateinit var accountViewModel: AccountViewModel
|
||||
@@ -160,6 +165,10 @@ open class NewProductViewModel :
|
||||
var wantsToMarkAsSensitive by mutableStateOf(false)
|
||||
var contentWarningDescription by mutableStateOf("")
|
||||
|
||||
// Expiration Date (NIP-40)
|
||||
var wantsExpirationDate by mutableStateOf(false)
|
||||
override var expirationDate by mutableLongStateOf(TimeUtils.oneDayAhead())
|
||||
|
||||
// GeoHash
|
||||
var wantsToAddGeoHash by mutableStateOf(false)
|
||||
var location: StateFlow<LocationState.LocationResult>? = null
|
||||
@@ -254,6 +263,10 @@ open class NewProductViewModel :
|
||||
wantsToMarkAsSensitive = draftEvent.isSensitive()
|
||||
contentWarningDescription = draftEvent.contentWarningReason() ?: ""
|
||||
|
||||
val draftExpiration = draftEvent.expiration()
|
||||
wantsExpirationDate = draftExpiration != null
|
||||
expirationDate = draftExpiration ?: TimeUtils.oneDayAhead()
|
||||
|
||||
val geohash = draftEvent.getGeoHash()
|
||||
wantsToAddGeoHash = geohash != null
|
||||
|
||||
@@ -333,6 +346,7 @@ open class NewProductViewModel :
|
||||
val zapReceiver = if (wantsForwardZapTo) forwardZapTo.value.toZapSplitSetup() else null
|
||||
val localZapRaiserAmount = if (wantsZapraiser) zapRaiserAmount.value else null
|
||||
val contentWarningReason = if (wantsToMarkAsSensitive) contentWarningDescription else null
|
||||
val localExpirationDate = if (wantsExpirationDate) expirationDate else null
|
||||
|
||||
val quotes = findNostrUris(tagger.message)
|
||||
|
||||
@@ -353,6 +367,7 @@ open class NewProductViewModel :
|
||||
localZapRaiserAmount?.let { zapraiser(it) }
|
||||
zapReceiver?.let { zapSplits(it) }
|
||||
contentWarningReason?.let { contentWarning(it) }
|
||||
localExpirationDate?.let { expiration(it) }
|
||||
|
||||
emojis(emojis)
|
||||
imetas(usedAttachments)
|
||||
@@ -618,6 +633,14 @@ open class NewProductViewModel :
|
||||
draftTag.newVersion()
|
||||
}
|
||||
|
||||
fun toggleExpirationDate() {
|
||||
wantsExpirationDate = !wantsExpirationDate
|
||||
if (wantsExpirationDate) {
|
||||
expirationDate = TimeUtils.oneDayAhead()
|
||||
}
|
||||
draftTag.newVersion()
|
||||
}
|
||||
|
||||
fun updateTitle(it: TextFieldValue) {
|
||||
title = it
|
||||
draftTag.newVersion()
|
||||
|
||||
+4
-2
@@ -56,6 +56,7 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.VoiceAnonymizationControlle
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.VoicePreset
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.draftTags.DraftTagState
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.EmojiSuggestionState
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.IExpiration
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.location.ILocationGrabber
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.messagefield.IMessageField
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.previews.PreviewState
|
||||
@@ -144,7 +145,8 @@ open class ShortNotePostViewModel :
|
||||
ILocationGrabber,
|
||||
IMessageField,
|
||||
IZapField,
|
||||
IZapRaiser {
|
||||
IZapRaiser,
|
||||
IExpiration {
|
||||
val draftTag = DraftTagState()
|
||||
|
||||
lateinit var accountViewModel: AccountViewModel
|
||||
@@ -242,7 +244,7 @@ open class ShortNotePostViewModel :
|
||||
|
||||
// Expiration Date (NIP-40)
|
||||
var wantsExpirationDate by mutableStateOf(false)
|
||||
var expirationDate by mutableLongStateOf(TimeUtils.oneDayAhead())
|
||||
override var expirationDate by mutableLongStateOf(TimeUtils.oneDayAhead())
|
||||
|
||||
// GeoHash
|
||||
var wantsToAddGeoHash by mutableStateOf(false)
|
||||
|
||||
+15
@@ -70,6 +70,8 @@ import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.ContentSensiti
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.MarkAsSensitiveButton
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.ShowEmojiSuggestionList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDateButton
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker
|
||||
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
|
||||
@@ -218,6 +220,15 @@ fun PublicMessageScreenContent(
|
||||
)
|
||||
}
|
||||
|
||||
if (postViewModel.wantsExpirationDate) {
|
||||
Row(
|
||||
verticalAlignment = CenterVertically,
|
||||
modifier = Modifier.padding(vertical = Size5dp, horizontal = Size10dp),
|
||||
) {
|
||||
ExpirationDatePicker(postViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
if (postViewModel.wantsToAddGeoHash) {
|
||||
LocationAsHash(postViewModel)
|
||||
}
|
||||
@@ -350,6 +361,10 @@ private fun BottomRowActions(
|
||||
postViewModel.toggleMarkAsSensitive()
|
||||
}
|
||||
|
||||
ExpirationDateButton(postViewModel.wantsExpirationDate) {
|
||||
postViewModel.toggleExpirationDate()
|
||||
}
|
||||
|
||||
AddGeoHashButton(postViewModel.wantsToAddGeoHash) {
|
||||
postViewModel.wantsToAddGeoHash = !postViewModel.wantsToAddGeoHash
|
||||
}
|
||||
|
||||
+24
-1
@@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.publicMessag
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableLongStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
@@ -48,6 +49,7 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMediaProcessing
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.draftTags.DraftTagState
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.EmojiSuggestionState
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.expiration.IExpiration
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.location.ILocationGrabber
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.messagefield.IMessageField
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.previews.PreviewState
|
||||
@@ -86,6 +88,7 @@ import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarning
|
||||
import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarningReason
|
||||
import com.vitorpamplona.quartz.nip36SensitiveContent.isSensitive
|
||||
import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent
|
||||
import com.vitorpamplona.quartz.nip40Expiration.expiration
|
||||
import com.vitorpamplona.quartz.nip57Zaps.splits.ZapSplitSetup
|
||||
import com.vitorpamplona.quartz.nip57Zaps.splits.zapSplitSetup
|
||||
import com.vitorpamplona.quartz.nip57Zaps.splits.zapSplits
|
||||
@@ -104,6 +107,7 @@ import com.vitorpamplona.quartz.nip94FileMetadata.sensitiveContent
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.size
|
||||
import com.vitorpamplona.quartz.utils.Hex
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
@@ -116,7 +120,8 @@ class NewPublicMessageViewModel :
|
||||
ILocationGrabber,
|
||||
IMessageField,
|
||||
IZapField,
|
||||
IZapRaiser {
|
||||
IZapRaiser,
|
||||
IExpiration {
|
||||
val draftTag = DraftTagState()
|
||||
|
||||
lateinit var accountViewModel: AccountViewModel
|
||||
@@ -171,6 +176,10 @@ class NewPublicMessageViewModel :
|
||||
var wantsToMarkAsSensitive by mutableStateOf(false)
|
||||
var contentWarningDescription by mutableStateOf("")
|
||||
|
||||
// Expiration Date (NIP-40)
|
||||
var wantsExpirationDate by mutableStateOf(false)
|
||||
override var expirationDate by mutableLongStateOf(TimeUtils.oneDayAhead())
|
||||
|
||||
// GeoHash
|
||||
var wantsToAddGeoHash by mutableStateOf(false)
|
||||
var location: StateFlow<LocationState.LocationResult>? = null
|
||||
@@ -270,6 +279,10 @@ class NewPublicMessageViewModel :
|
||||
wantsToMarkAsSensitive = draftEvent.isSensitive()
|
||||
contentWarningDescription = draftEvent.contentWarningReason() ?: ""
|
||||
|
||||
val draftExpiration = draftEvent.expiration()
|
||||
wantsExpirationDate = draftExpiration != null
|
||||
expirationDate = draftExpiration ?: TimeUtils.oneDayAhead()
|
||||
|
||||
val geohash = draftEvent.getGeoHash()
|
||||
wantsToAddGeoHash = geohash != null
|
||||
|
||||
@@ -368,6 +381,7 @@ class NewPublicMessageViewModel :
|
||||
val usedAttachments = iMetaAttachments.filterIsIn(urls.toSet())
|
||||
|
||||
val contentWarningReason = if (wantsToMarkAsSensitive) contentWarningDescription else null
|
||||
val localExpirationDate = if (wantsExpirationDate) expirationDate else null
|
||||
|
||||
return PublicMessageEvent.build(
|
||||
to = toUsers.toList(),
|
||||
@@ -381,6 +395,7 @@ class NewPublicMessageViewModel :
|
||||
localZapRaiserAmount?.let { zapraiser(it) }
|
||||
zapReceiver?.let { zapSplits(it) }
|
||||
contentWarningReason?.let { contentWarning(it) }
|
||||
localExpirationDate?.let { expiration(it) }
|
||||
|
||||
emojis(emojis)
|
||||
imetas(usedAttachments)
|
||||
@@ -663,5 +678,13 @@ class NewPublicMessageViewModel :
|
||||
draftTag.newVersion()
|
||||
}
|
||||
|
||||
fun toggleExpirationDate() {
|
||||
wantsExpirationDate = !wantsExpirationDate
|
||||
if (wantsExpirationDate) {
|
||||
expirationDate = TimeUtils.oneDayAhead()
|
||||
}
|
||||
draftTag.newVersion()
|
||||
}
|
||||
|
||||
override fun locationManager(): LocationState = Amethyst.instance.locationManager
|
||||
}
|
||||
|
||||
+3
@@ -91,6 +91,7 @@ import com.vitorpamplona.amethyst.ui.note.CheckAndDisplayEditStatus
|
||||
import com.vitorpamplona.amethyst.ui.note.CheckHiddenFeedWatchBlockAndReport
|
||||
import com.vitorpamplona.amethyst.ui.note.DisplayDraft
|
||||
import com.vitorpamplona.amethyst.ui.note.DisplayOtsIfInOriginal
|
||||
import com.vitorpamplona.amethyst.ui.note.Expiration
|
||||
import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote
|
||||
import com.vitorpamplona.amethyst.ui.note.LongPressToQuickAction
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture
|
||||
@@ -483,6 +484,8 @@ private fun FullBleedNoteCompose(
|
||||
|
||||
CheckAndDisplayEditStatus(editState)
|
||||
|
||||
Expiration(baseNote)
|
||||
|
||||
TimeAgo(note = baseNote)
|
||||
|
||||
MoreOptionsButton(baseNote, editState, accountViewModel, nav)
|
||||
|
||||
@@ -1538,6 +1538,7 @@
|
||||
<string name="crashreport_found">Crash Report found</string>
|
||||
<string name="would_you_like_to_send_the_recent_crash_report_to_amethyst_in_a_dm_no_personal_information_will_be_shared">Would you like to send the recent crash report to Amethyst in a DM? No personal information will be shared</string>
|
||||
<string name="crashreport_found_send">Send it</string>
|
||||
<string name="this_message_will_disappear_in">This message will disappear in %1$s</string>
|
||||
<string name="this_message_will_disappear_in_days">This message will disappear in %1$d days</string>
|
||||
<string name="select_signer">Select Signer</string>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user