mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-07-22 07:48:27 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f42881a48e | ||
|
|
6fc72f47bb | ||
|
|
041c788e21 |
@@ -745,8 +745,8 @@ android {
|
||||
applicationId = "com.vitorpamplona.amethyst"
|
||||
minSdk = 26 // Android 8.0 (Oreo)
|
||||
targetSdk = 36 // Android 15
|
||||
versionCode = 434
|
||||
versionName = "1.06.2"
|
||||
versionCode = 435
|
||||
versionName = "1.06.3"
|
||||
|
||||
vectorDrawables {
|
||||
useSupportLibrary = true
|
||||
|
||||
@@ -7,7 +7,7 @@ description: Integration guide for using the Quartz Nostr KMP library in externa
|
||||
|
||||
Reference for integrating `com.vitorpamplona.quartz:quartz` into external Nostr KMP projects.
|
||||
|
||||
**Published artifact**: `com.vitorpamplona.quartz:quartz:1.06.2` (Maven Central)
|
||||
**Published artifact**: `com.vitorpamplona.quartz:quartz:1.06.3` (Maven Central)
|
||||
**Targets**: JVM 21+, Android (minSdk 21+), iOS (XCFramework `quartz-kmpKit`)
|
||||
**License**: MIT
|
||||
|
||||
@@ -19,7 +19,7 @@ Reference for integrating `com.vitorpamplona.quartz:quartz` into external Nostr
|
||||
|
||||
```toml
|
||||
[versions]
|
||||
quartz = "1.06.2"
|
||||
quartz = "1.06.3"
|
||||
|
||||
[libraries]
|
||||
quartz = { module = "com.vitorpamplona.quartz:quartz", version.ref = "quartz" }
|
||||
@@ -41,7 +41,7 @@ kotlin {
|
||||
|
||||
```kotlin
|
||||
dependencies {
|
||||
implementation("com.vitorpamplona.quartz:quartz:1.06.2")
|
||||
implementation("com.vitorpamplona.quartz:quartz:1.06.3")
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Current version
|
||||
|
||||
```
|
||||
com.vitorpamplona.quartz:quartz:1.06.2
|
||||
com.vitorpamplona.quartz:quartz:1.06.3
|
||||
```
|
||||
|
||||
Check latest: https://central.sonatype.com/artifact/com.vitorpamplona.quartz/quartz
|
||||
@@ -16,7 +16,7 @@ Check latest: https://central.sonatype.com/artifact/com.vitorpamplona.quartz/qua
|
||||
|
||||
```toml
|
||||
[versions]
|
||||
quartz = "1.06.2"
|
||||
quartz = "1.06.3"
|
||||
|
||||
[libraries]
|
||||
quartz = { module = "com.vitorpamplona.quartz:quartz", version.ref = "quartz" }
|
||||
@@ -55,7 +55,7 @@ kotlin {
|
||||
```kotlin
|
||||
// build.gradle.kts (app module)
|
||||
dependencies {
|
||||
implementation("com.vitorpamplona.quartz:quartz:1.06.2")
|
||||
implementation("com.vitorpamplona.quartz:quartz:1.06.3")
|
||||
}
|
||||
```
|
||||
|
||||
@@ -70,7 +70,7 @@ plugins {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("com.vitorpamplona.quartz:quartz:1.06.2")
|
||||
implementation("com.vitorpamplona.quartz:quartz:1.06.3")
|
||||
// JNA needed for libsodium (NIP-44) on JVM
|
||||
implementation("net.java.dev.jna:jna:5.18.1")
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ The Quartz library was successfully converted from Android-only to full KMP supp
|
||||
## Current artifact
|
||||
|
||||
```
|
||||
com.vitorpamplona.quartz:quartz:1.06.2
|
||||
com.vitorpamplona.quartz:quartz:1.06.3
|
||||
```
|
||||
|
||||
See `.claude/skills/quartz-integration/SKILL.md` for full integration guide.
|
||||
@@ -54,8 +54,8 @@ android {
|
||||
applicationId = "com.vitorpamplona.amethyst"
|
||||
minSdk = libs.versions.android.minSdk.get().toInteger()
|
||||
targetSdk = libs.versions.android.targetSdk.get().toInteger()
|
||||
versionCode = 434
|
||||
versionName = generateVersionName("1.06.2")
|
||||
versionCode = 435
|
||||
versionName = generateVersionName("1.06.3")
|
||||
buildConfigField "String", "RELEASE_NOTES_ID", "\"0b6af7660b44215b0edf9c39a1c9c0b4aafba7aba1ae28665ffcecb1a9717195\""
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
@@ -1300,9 +1300,18 @@ class Account(
|
||||
val anonymousSigner = NostrSignerInternal(KeyPair())
|
||||
val event = anonymousSigner.sign(template)
|
||||
|
||||
val relayList = nip65RelayList.outboxFlow.value.toSet()
|
||||
cache.justConsumeMyOwnEvent(event)
|
||||
val note =
|
||||
if (event is AddressableEvent) {
|
||||
cache.getOrCreateAddressableNote(event.address())
|
||||
} else {
|
||||
cache.getOrCreateNote(event.id)
|
||||
}
|
||||
|
||||
val relayList = computeRelayListToBroadcast(note)
|
||||
|
||||
client.send(event, relayList)
|
||||
|
||||
broadcast.forEach { client.send(it, relayList) }
|
||||
|
||||
return event
|
||||
|
||||
@@ -194,6 +194,8 @@ open class CommentPostViewModel :
|
||||
var wantsZapraiser by mutableStateOf(false)
|
||||
override val zapRaiserAmount = mutableStateOf<Long?>(null)
|
||||
|
||||
var wantsAnonymousPost by mutableStateOf(false)
|
||||
|
||||
fun lnAddress(): String? = account.userProfile().lnAddress()
|
||||
|
||||
fun hasLnAddress(): Boolean = account.userProfile().lnAddress() != null
|
||||
@@ -342,10 +344,15 @@ open class CommentPostViewModel :
|
||||
}
|
||||
|
||||
val version = draftTag.current
|
||||
|
||||
val anonymous = wantsAnonymousPost
|
||||
cancel()
|
||||
|
||||
accountViewModel.account.signAndComputeBroadcast(template, extraNotesToBroadcast)
|
||||
if (anonymous) {
|
||||
accountViewModel.account.signAnonymouslyAndBroadcast(template, extraNotesToBroadcast)
|
||||
} else {
|
||||
accountViewModel.account.signAndComputeBroadcast(template, extraNotesToBroadcast)
|
||||
}
|
||||
|
||||
accountViewModel.viewModelScope.launch(Dispatchers.IO) {
|
||||
accountViewModel.account.deleteDraftIgnoreErrors(version)
|
||||
}
|
||||
@@ -588,6 +595,7 @@ open class CommentPostViewModel :
|
||||
contentWarningDescription = ""
|
||||
wantsToAddGeoHash = false
|
||||
wantsSecretEmoji = false
|
||||
wantsAnonymousPost = false
|
||||
|
||||
forwardZapTo.value = SplitBuilder()
|
||||
forwardZapToEditting.value = TextFieldValue("")
|
||||
|
||||
@@ -22,7 +22,9 @@ package com.vitorpamplona.amethyst.ui.note.nip22Comments
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -35,6 +37,8 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
@@ -79,9 +83,12 @@ import com.vitorpamplona.amethyst.ui.note.creators.zapraiser.ZapRaiserRequest
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.ForwardZapTo
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.ForwardZapToButton
|
||||
import com.vitorpamplona.amethyst.ui.note.types.ReplyRenderType
|
||||
import com.vitorpamplona.amethyst.ui.painterRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size30Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size35Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.SuggestionListDefaultHeightPage
|
||||
@@ -241,11 +248,32 @@ private fun GenericCommentPostBody(
|
||||
Row(
|
||||
modifier = Modifier.padding(vertical = Size10dp),
|
||||
) {
|
||||
BaseUserPicture(
|
||||
accountViewModel.userProfile(),
|
||||
Size35dp,
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
if (postViewModel.wantsAnonymousPost) {
|
||||
IconButton(
|
||||
modifier = Size35Modifier,
|
||||
onClick = { postViewModel.wantsAnonymousPost = false },
|
||||
) {
|
||||
Icon(
|
||||
painter = painterRes(resourceId = R.drawable.incognito, 1),
|
||||
contentDescription = stringRes(R.string.post_anonymously),
|
||||
modifier = Size30Modifier,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Box(
|
||||
modifier =
|
||||
Modifier.clickable {
|
||||
postViewModel.wantsAnonymousPost = true
|
||||
},
|
||||
) {
|
||||
BaseUserPicture(
|
||||
accountViewModel.userProfile(),
|
||||
Size35dp,
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
}
|
||||
}
|
||||
MessageField(
|
||||
R.string.what_s_on_your_mind,
|
||||
postViewModel,
|
||||
|
||||
@@ -28,6 +28,8 @@ import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
@@ -134,11 +136,13 @@ fun ChatFeedLoaded(
|
||||
}
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
val highlightedNoteId = remember { mutableStateOf<String?>(null) }
|
||||
val onScrollToNote: (Note) -> Unit = { note ->
|
||||
val index = items.list.indexOfFirst { it.idHex == note.idHex }
|
||||
if (index >= 0) {
|
||||
scope.launch {
|
||||
listState.animateScrollToItem(index)
|
||||
highlightedNoteId.value = note.idHex
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,6 +164,8 @@ fun ChatFeedLoaded(
|
||||
onWantsToReply = onWantsToReply,
|
||||
onWantsToEditDraft = onWantsToEditDraft,
|
||||
onScrollToNote = onScrollToNote,
|
||||
shouldHighlight = highlightedNoteId.value == item.idHex,
|
||||
onHighlightFinished = { highlightedNoteId.value = null },
|
||||
)
|
||||
|
||||
NewDateOrSubjectDivisor(items.list.getOrNull(index + 1), item)
|
||||
|
||||
@@ -96,6 +96,8 @@ fun ChatroomMessageCompose(
|
||||
onWantsToReply: (Note) -> Unit,
|
||||
onWantsToEditDraft: (Note) -> Unit,
|
||||
onScrollToNote: ((Note) -> Unit)? = null,
|
||||
shouldHighlight: Boolean = false,
|
||||
onHighlightFinished: (() -> Unit)? = null,
|
||||
) {
|
||||
WatchNoteEvent(baseNote = baseNote, accountViewModel = accountViewModel, nav) {
|
||||
WatchBlockAndReport(
|
||||
@@ -116,6 +118,8 @@ fun ChatroomMessageCompose(
|
||||
onWantsToReply,
|
||||
onWantsToEditDraft,
|
||||
onScrollToNote,
|
||||
shouldHighlight,
|
||||
onHighlightFinished,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -133,6 +137,8 @@ fun NormalChatNote(
|
||||
onWantsToReply: (Note) -> Unit,
|
||||
onWantsToEditDraft: (Note) -> Unit,
|
||||
onScrollToNote: ((Note) -> Unit)? = null,
|
||||
shouldHighlight: Boolean = false,
|
||||
onHighlightFinished: (() -> Unit)? = null,
|
||||
) {
|
||||
val isLoggedInUser =
|
||||
remember(note.author) {
|
||||
@@ -170,6 +176,8 @@ fun NormalChatNote(
|
||||
hasDetailsToShow = note.zaps.isNotEmpty() || note.zapPayments.isNotEmpty() || note.reactions.isNotEmpty(),
|
||||
drawAuthorInfo = drawAuthorInfo,
|
||||
parentBackgroundColor = parentBackgroundColor,
|
||||
shouldHighlight = shouldHighlight,
|
||||
onHighlightFinished = onHighlightFinished,
|
||||
onClick = {
|
||||
if (note.event is ChannelCreateEvent) {
|
||||
nav.nav(Route.PublicChatChannel(note.idHex))
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.layouts
|
||||
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -36,7 +38,9 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -58,6 +62,7 @@ import com.vitorpamplona.amethyst.ui.theme.chatBackground
|
||||
import com.vitorpamplona.amethyst.ui.theme.chatDraftBackground
|
||||
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
||||
import com.vitorpamplona.amethyst.ui.theme.messageBubbleLimits
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
private const val RELAYS_AND_ACTIONS_TEXT = "Relays and Actions"
|
||||
|
||||
@@ -71,6 +76,8 @@ fun ChatBubbleLayout(
|
||||
hasDetailsToShow: Boolean,
|
||||
drawAuthorInfo: Boolean,
|
||||
parentBackgroundColor: MutableState<Color>? = null,
|
||||
shouldHighlight: Boolean = false,
|
||||
onHighlightFinished: (() -> Unit)? = null,
|
||||
onClick: () -> Boolean,
|
||||
onAuthorClick: () -> Unit,
|
||||
actionMenu: @Composable (onDismiss: () -> Unit) -> Unit,
|
||||
@@ -100,6 +107,24 @@ fun ChatBubbleLayout(
|
||||
}
|
||||
}
|
||||
|
||||
val highlightActive = remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(shouldHighlight) {
|
||||
if (shouldHighlight) {
|
||||
highlightActive.value = true
|
||||
delay(1500)
|
||||
highlightActive.value = false
|
||||
onHighlightFinished?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
val highlightColor = MaterialTheme.colorScheme.secondary.copy(alpha = 0.3f)
|
||||
val animatedColor by animateColorAsState(
|
||||
targetValue = if (highlightActive.value) highlightColor.compositeOver(bgColor.value) else bgColor.value,
|
||||
animationSpec = tween(durationMillis = if (highlightActive.value) 300 else 800),
|
||||
label = "highlightAnimation",
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier = if (innerQuote) ChatPaddingInnerQuoteModifier else ChatPaddingModifier,
|
||||
horizontalArrangement = if (isLoggedInUser) Arrangement.End else Arrangement.Start,
|
||||
@@ -136,7 +161,7 @@ fun ChatBubbleLayout(
|
||||
modifier = if (innerQuote) Modifier else ChatBubbleMaxSizeModifier,
|
||||
) {
|
||||
Surface(
|
||||
color = bgColor.value,
|
||||
color = animatedColor,
|
||||
shape = if (isLoggedInUser) ChatBubbleShapeMe else ChatBubbleShapeThem,
|
||||
modifier = clickableModifier,
|
||||
) {
|
||||
|
||||
@@ -25,7 +25,6 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Parcelable
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -49,7 +48,6 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -110,6 +108,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsRow
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size19Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size30Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size35Modifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
@@ -288,23 +287,6 @@ private fun NewPostScreenBody(
|
||||
}
|
||||
}
|
||||
|
||||
if (postViewModel.wantsAnonymousPost) {
|
||||
Row(
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.background(MaterialTheme.colorScheme.errorContainer)
|
||||
.padding(horizontal = Size10dp, vertical = 8.dp),
|
||||
verticalAlignment = CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = stringRes(R.string.anonymous_reply_warning),
|
||||
color = MaterialTheme.colorScheme.onErrorContainer,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Only show text input if no voice message is being posted
|
||||
if (postViewModel.voiceMetadata == null && postViewModel.voiceRecording == null) {
|
||||
Row(
|
||||
@@ -312,12 +294,13 @@ private fun NewPostScreenBody(
|
||||
) {
|
||||
if (postViewModel.wantsAnonymousPost) {
|
||||
IconButton(
|
||||
modifier = Size35Modifier,
|
||||
onClick = { postViewModel.wantsAnonymousPost = false },
|
||||
) {
|
||||
Icon(
|
||||
painter = painterRes(resourceId = R.drawable.incognito, 1),
|
||||
contentDescription = stringRes(R.string.post_anonymously),
|
||||
modifier = Size35Modifier,
|
||||
modifier = Size30Modifier,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -350,7 +350,7 @@ mavenPublishing {
|
||||
coordinates(
|
||||
groupId = "com.vitorpamplona.quartz",
|
||||
artifactId = "quartz",
|
||||
version = "1.06.2",
|
||||
version = "1.06.3",
|
||||
)
|
||||
|
||||
// Configure publishing to Maven Central
|
||||
|
||||
Reference in New Issue
Block a user