This commit is contained in:
Vitor Pamplona
2026-05-20 18:59:05 -04:00
parent ee67ba6408
commit e0abc4a224
11 changed files with 251 additions and 123 deletions
+2 -2
View File
@@ -745,8 +745,8 @@ android {
applicationId = "com.vitorpamplona.amethyst"
minSdk = 26 // Android 8.0 (Oreo)
targetSdk = 36 // Android 15
versionCode = 446
versionName = "1.10.0"
versionCode = 447
versionName = "1.11.0"
vectorDrawables {
useSupportLibrary = true
+3 -3
View File
@@ -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.10.0` (Maven Central)
**Published artifact**: `com.vitorpamplona.quartz:quartz:1.11.0` (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.10.0"
quartz = "1.11.0"
[libraries]
quartz = { module = "com.vitorpamplona.quartz:quartz", version.ref = "quartz" }
@@ -41,7 +41,7 @@ kotlin {
```kotlin
dependencies {
implementation("com.vitorpamplona.quartz:quartz:1.10.0")
implementation("com.vitorpamplona.quartz:quartz:1.11.0")
}
```
@@ -3,7 +3,7 @@
## Current version
```
com.vitorpamplona.quartz:quartz:1.10.0
com.vitorpamplona.quartz:quartz:1.11.0
```
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.10.0"
quartz = "1.11.0"
[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.10.0")
implementation("com.vitorpamplona.quartz:quartz:1.11.0")
}
```
@@ -70,7 +70,7 @@ plugins {
}
dependencies {
implementation("com.vitorpamplona.quartz:quartz:1.10.0")
implementation("com.vitorpamplona.quartz:quartz:1.11.0")
// JNA needed for libsodium (NIP-44) on JVM
implementation("net.java.dev.jna:jna:5.18.1")
}
+1 -1
View File
@@ -17,7 +17,7 @@ The Quartz library was successfully converted from Android-only to full KMP supp
## Current artifact
```
com.vitorpamplona.quartz:quartz:1.10.0
com.vitorpamplona.quartz:quartz:1.11.0
```
See `.claude/skills/quartz-integration/SKILL.md` for full integration guide.
+9 -9
View File
@@ -113,7 +113,7 @@ Where:
| Field | Values |
|---|---------------------------------------------------------|
| `<version>` | Tag stripped of leading `v` (e.g. `1.10.0`) |
| `<version>` | Tag stripped of leading `v` (e.g. `1.11.0`) |
| `<family>` | `macos`, `windows`, `linux` |
| `<arch>` | `x64`, `arm64` |
| `<ext>` | `dmg`, `msi`, `zip`, `deb`, `rpm`, `AppImage`, `tar.gz` |
@@ -124,10 +124,10 @@ any change is a breaking contract.
Examples:
- `amethyst-desktop-1.10.0-macos-x64.dmg`
- `amethyst-desktop-1.10.0-macos-arm64.dmg`
- `amethyst-desktop-1.10.0-windows-x64.msi`
- `amethyst-desktop-1.10.0-linux-x64.AppImage`
- `amethyst-desktop-1.11.0-macos-x64.dmg`
- `amethyst-desktop-1.11.0-macos-arm64.dmg`
- `amethyst-desktop-1.11.0-windows-x64.msi`
- `amethyst-desktop-1.11.0-linux-x64.AppImage`
---
@@ -147,7 +147,7 @@ Quartz library in one pipeline.
must increment even for same `versionName`):
```groovy
versionCode = 443
versionCode = 447
versionName = generateVersionName(libs.versions.app.get())
```
@@ -223,8 +223,8 @@ or equivalent issue tracker. On rotation, paste new token and run
```bash
brew bump-cask-pr amethyst-nostr \
--version 1.10.0 \
--url "https://github.com/vitorpamplona/amethyst/releases/download/v1.10.0/amethyst-desktop-1.10.0-macos-arm64.dmg"
--version 1.11.0 \
--url "https://github.com/vitorpamplona/amethyst/releases/download/v1.11.0/amethyst-desktop-1.11.0-macos-arm64.dmg"
```
The cask filename is `amethyst-nostr` (not `amethyst` — that's taken by a
@@ -235,7 +235,7 @@ auto-submits new version bumps on each stable release.
```bash
wingetcreate new \
https://github.com/vitorpamplona/amethyst/releases/download/v1.10.0/amethyst-desktop-1.10.0-windows-x64.msi
https://github.com/vitorpamplona/amethyst/releases/download/v1.11.0/amethyst-desktop-1.11.0-windows-x64.msi
```
Set `PackageIdentifier = VitorPamplona.Amethyst`. After the first manifest is
+105
View File
@@ -1,3 +1,108 @@
<a id="v1.11.0"></a> NIP-52 Calendars, On-Chain Zap Polish
Highlights:
- NIP-52 Calendars — feed, day/week/month views, event/collection editors, RSVP, ICS export, "starting soon" notifications, share-as-nostr-link, gallery picker.
- On-Chain zaps polish — splits with dust gating, payment-targets modal redesign (QR + copy + pay), public-address chip + confirmation, on-chain handoff from custom-zap dialog, on-chain zappers in the reactions gallery.
- Privacy groundwork — I2P scaffolded as a parallel transport to Tor, route-aware HTTP stack, typed fail-closed `BlockedRouteException`.
- Notifications — dedicated settings screen, delivery vs display split, on-chain zaps in summary stats, push filters aligned with the Notifications feed.
- Inline nowhere-link cards in rich text.
- Wallet — clickable on-chain rows, tappable wallet card opens transaction history, reactive on-chain zap observation, time-windowed relay sub with burst coalescing.
PRs:
- Restore Lightning Address + LNURL fields in Edit Profile
- Raise the default maximum hashtag limit from 5 to 8
- Include on-chain zaps in notification summary stats
- Add electrum.nmc.ethicnology.com to default ElectrumX server set
- Translate call-permission and git-repo strings (cs, pt-BR, sv, de) + New Crowdin translations
- Subscribe and observe PaymentTargetsEvent for other users
- Only bridge to local cache when URL is BUD-01 layout; dedupe public-channel rows; normalize video/x-m4v to video/mp4
- Enable Send when typed name resolves via NIP-05; on-chain Bit recipient
- Inline Namecoin resolution indicator + result row on on-chain zaps
- Inline Namecoin resolution indicator in global search bar
- Long-press to copy Nostr Address, Website, LN Address, identities, payment targets
- macOS VLC bundled discovery and video rendering
- Make RelayAuthenticator authStatus thread-safe
- Pad GitRepositoryOverview content to clear top/bottom bars
- Use LargeCache for RelayAuthenticator authStatus
- MIME-type normalization for MediaStore
- Split delivery vs display, add Categories section in notifications
- Accept floating-point dimensions in imeta so image space is reserved pre-load
- Explain hashtag-limit hide reason in HiddenNote
- Route media-upload signing through launchSigner
- Render nowhere links inline as branded cards
- Release MediaController after 30s in background; skip timer for PiP
- Clickable on-chain card opens transaction history; tappable on-chain rows + txid index in LocalCache
- Disable ProGuard optimization entirely on desktop (fixes kmp-tor crash); .deb launch CI smoke test
- Show on-chain zappers in expanded reactions gallery
- Convert hashtag-limit message to <plurals> and add cs/pt-BR/sv/de translations
- Restore long-press on root note + anchor popup to the card
- Keep filter chips visible on empty on-chain transactions list
- Make playback notification tap open the note on warm-pool resume
- Validate zap receipts against LNURL provider's nostrPubkey (NIP-57 Appendix F)
- Stable sort in ShortsFeedFilter to avoid TimSort contract crash
- Align push notifications with Notifications feed filter; resolve addressable events to their replaceable note; WakeUp bypass + lookup hoist
- Update on-chain-zap + headers-explorer plans for NIP-BC inline SPV tags
- Start zoomable dialog close animation from zoomed bounds
- Scaffold I2P as a parallel privacy transport to Tor; route-aware HTTP stack; BlockedRouteException
- Reorder feed filter popup sections (DVMs before Communities, interest sets next to hashtags)
- Stop spinning Around Me when Geocoder is unavailable
- NIP-52 calendars — feed, day/week/month views, RSVP, ICS export, reminders, edit, share-as-nostr-link, participant picker, multi-day bars
- Audit follow-ups on MLS reply paths; route reply button on MLS messages to the encrypted group
- Use LaunchedEffect instead of remember for VM reset
- Switch to Dispatchers.IO around the whole executeAsync call in relay-info
- Drop crossfade around the card feed in notifications
- Observe locale in CalendarDateTimePickerButton
- Modernize zap amount choice popup to match reactions popup style
- Catch ForegroundServiceStartNotAllowedException in PlaybackService
- Include crashing thread name in crash report
- Convert remaining .gradle files to Kotlin DSL
- Redesign payment targets modal with QR, copy and pay buttons
- Add Public chip to on-chain wallet card; clarify privacy guidance on on-chain wallet popup
- Require running material-symbols-subset.sh when adding new icons; add new information icon
- Re-add Nostrcheck.me Blossom server to defaults
- Surface on-chain zaps from the reactions zap button
- On-chain zap splits — drop sender from splits, merge duplicates, gate Send on dust
- On-chain option on the Zap the Devs button
- On-chain handoff from the custom-zap dialog
- Keep listening on default index+search relays for users with no kind 10002
- Skip offline relays when fetching user metadata
- Include indexer and proxy relays in the trusted relay list to avoid Tor
- Confirm on-chain copy with public-address warning
- Swallow LegacyCursorAnchorInfo IllegalArgumentException
- Render ContactListEvent in NoteCompose with tap-through user list; add preview for DisplayContactList
## Contributors
- @npub1gcxzte5zlkncx26j68ez60fzkvtkm9e0vrwdcvsjakxf9mu9qewqlfnj5z
- @npub1e2yuky03caw4ke3zy68lg0fz3r4gkt94hx4fjmlelacyljgyk79svn3eef
- @npub12cfje6nl2nuxplcqfvhg7ljt89fmpj0n0fd24zxsukja5qm9wmtqd7y76c
- @npub1w4uswmv6lu9yel005l3qgheysmr7tk9uvwluddznju3nuxalevvs2d0jr5
- @npub1a3tx8wcrt789skl6gg7rqwj4wey0j53eesr4z6asd4h4jwrd62jq0wkq4k
- @npub1dn0tej4a5806qk9ts56j572sndvjk27l5qmsxf0z3mquknccve7s4k8tfp
## Translations
- Czech, German, Swedish, and Portuguese by @npub1e2yuky03caw4ke3zy68lg0fz3r4gkt94hx4fjmlelacyljgyk79svn3eef
- Hungarian by @npub1dnvslq0vvrs8d603suykc4harv94yglcxwna9sl2xu8grt2afm3qgfh0tp
- French by @npub106efcyntxc5qwl3w8krrhyt626m59ya2nk9f40px5s968u5xdwhsjsr8fz
- Dutch by @npub1w4la29u3zv09r6crx5u8yxax0ffxgekzdm2egzjkjckef7xc83fs0ftxcd
- Polish by @npub16gjyljum0ksrrm28zzvejydgxwfm7xse98zwc4hlgq8epxeuggushqwyrm
- Hindi by @npub1ww6huwu3xye6r05n3qkjeq62wds5pq0jswhl7uc59lchc0n0ns4sdtw5e6
- Slovenian by @npub1qqqqqqz7nhdqz3uuwmzlflxt46lyu7zkuqhcapddhgz66c4ddynswreecw
- Bengali by @npub13qtw3yu0uc9r4yj5x0rhgy8nj5q0uyeq0pavkgt9ly69uuzxgkfqwvx23t
- Spanish by @npub1luhyzgce7qtcs6r6v00ryjxza8av8u4dzh3avg0zks38tjktnmxspxq903
- Chinese by hypnotichemionus4 and @npub1gd8e0xfkylc7v8c5a6hkpj4gelwwcy99jt90lqjseqjj2t253s2s6ch58h
- Russian by Anton Zhao
<a id="v1.10.0"></a> On-Chain zaps
- ci: remove macos-13 x64 build legs by @vitorpamplona in #2939
- Replace linuxdeploy with appimagetool for AppImage packaging by @vitorpamplona in #2940
- Sync inner note highlight fade with parent background color by @vitorpamplona in #2941
- Handle denied call permissions with settings dialog by @vitorpamplona in #2942
- Fix gradient rendering with transparent background colors by @vitorpamplona in #2943
- Add NIP-BC onchain Bitcoin zaps support (send, receive, display) by @vitorpamplona in #2944
<a id="v1.09.2"></a> Fixes
- Fix Blossom blob detection to reject non-compliant filenames by @greenart7c3 in #2919
+123 -100
View File
@@ -7,19 +7,23 @@ plugins {
alias(libs.plugins.serialization)
}
fun getCurrentBranch(): String {
return try {
val process = ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD")
.redirectErrorStream(true)
.start()
val branch = process.inputStream.bufferedReader().use { it.readText() }.trim()
fun getCurrentBranch(): String =
try {
val process =
ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD")
.redirectErrorStream(true)
.start()
val branch =
process.inputStream
.bufferedReader()
.use { it.readText() }
.trim()
process.waitFor()
branch
} catch (e: Exception) {
println("Could not determine git branch: ${e.message}")
"unknown"
}
}
fun generateVersionName(baseVersion: String): String {
val currentBranch = getCurrentBranch()
@@ -52,99 +56,109 @@ afterEvaluate {
android {
namespace = "com.vitorpamplona.amethyst"
compileSdk = libs.versions.android.compileSdk.get().toInt()
compileSdk =
libs.versions.android.compileSdk
.get()
.toInt()
defaultConfig {
applicationId = "com.vitorpamplona.amethyst"
minSdk = libs.versions.android.minSdk.get().toInt()
targetSdk = libs.versions.android.targetSdk.get().toInt()
versionCode = 446
minSdk =
libs.versions.android.minSdk
.get()
.toInt()
targetSdk =
libs.versions.android.targetSdk
.get()
.toInt()
versionCode = 447
versionName = generateVersionName(libs.versions.app.get())
buildConfigField("String", "RELEASE_NOTES_ID", "\"b1b91d7ee0c5da9d081d1a53470248ee4585b058b11aa34fe28c0e3e07ac1e0a\"")
buildConfigField("String", "RELEASE_NOTES_ID", "\"8ec0d94550b5538115226c6858159b1115713c9c6ed942173bd4fd5d292d8ba6\"")
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
@Suppress("UnstableApiUsage")
resourceConfigurations += listOf(
"ar",
"ar-rSA",
"bn-rBD",
"cs",
"cs-rCZ",
"cy-rGB",
"da-rDK",
"de",
"de-rDE",
"el-rGR",
"en-rGB",
"eo",
"eo-rUY",
"es",
"es-rES",
"es-rMX",
"es-rUS",
"et-rEE",
"fa",
"fa-rIR",
"fi-rFI",
"fo-rFO",
"fr",
"fr-rCA",
"fr-rFR",
"gu-rIN",
"hi-rIN",
"hr-rHR",
"hu",
"hu-rHU",
"in",
"in-rID",
"it-rIT",
"iw-rIL",
"ja",
"ja-rJP",
"kk-rKZ",
"ko-rKR",
"ks-rIN",
"ku-rTR",
"lt-rLT",
"ne-rNP",
"nl",
"nl-rBE",
"nl-rNL",
"pcm-rNG",
"pl-rPL",
"pt-rBR",
"pt-rPT",
"ru",
"ru-rRU",
"ru-rUA",
"sa-rIN",
"sl-rSI",
"so-rSO",
"sr-rSP",
"ss-rZA",
"sv-rSE",
"sw-rKE",
"sw-rTZ",
"ta",
"ta-rIN",
"th",
"th-rTH",
"tr",
"tr-rTR",
"uk",
"uk-rUA",
"ur-rIN",
"uz-rUZ",
"vi-rVN",
"zh",
"zh-rCN",
"zh-rHK",
"zh-rSG",
"zh-rTW",
)
resourceConfigurations +=
listOf(
"ar",
"ar-rSA",
"bn-rBD",
"cs",
"cs-rCZ",
"cy-rGB",
"da-rDK",
"de",
"de-rDE",
"el-rGR",
"en-rGB",
"eo",
"eo-rUY",
"es",
"es-rES",
"es-rMX",
"es-rUS",
"et-rEE",
"fa",
"fa-rIR",
"fi-rFI",
"fo-rFO",
"fr",
"fr-rCA",
"fr-rFR",
"gu-rIN",
"hi-rIN",
"hr-rHR",
"hu",
"hu-rHU",
"in",
"in-rID",
"it-rIT",
"iw-rIL",
"ja",
"ja-rJP",
"kk-rKZ",
"ko-rKR",
"ks-rIN",
"ku-rTR",
"lt-rLT",
"ne-rNP",
"nl",
"nl-rBE",
"nl-rNL",
"pcm-rNG",
"pl-rPL",
"pt-rBR",
"pt-rPT",
"ru",
"ru-rRU",
"ru-rUA",
"sa-rIN",
"sl-rSI",
"so-rSO",
"sr-rSP",
"ss-rZA",
"sv-rSE",
"sw-rKE",
"sw-rTZ",
"ta",
"ta-rIN",
"th",
"th-rTH",
"tr",
"tr-rTR",
"uk",
"uk-rUA",
"ur-rIN",
"uz-rUZ",
"vi-rVN",
"zh",
"zh-rCN",
"zh-rHK",
"zh-rSG",
"zh-rTW",
)
}
// Opt-in fast-build flags. Default behavior is unchanged.
@@ -162,12 +176,21 @@ android {
// much faster and outputs/mapping/ (~260MB)
// is not produced. Local-dev and PR-CI use
// only — release pipelines must not set it.
val disableAbiSplits = providers.gradleProperty("disableAbiSplits")
.map { it.toBoolean() }.getOrElse(false)
val disableUniversalApk = providers.gradleProperty("disableUniversalApk")
.map { it.toBoolean() }.getOrElse(false)
val skipMapping = providers.gradleProperty("amethyst.skipMapping")
.map { it.toBoolean() }.getOrElse(false)
val disableAbiSplits =
providers
.gradleProperty("disableAbiSplits")
.map { it.toBoolean() }
.getOrElse(false)
val disableUniversalApk =
providers
.gradleProperty("disableUniversalApk")
.map { it.toBoolean() }
.getOrElse(false)
val skipMapping =
providers
.gradleProperty("amethyst.skipMapping")
.map { it.toBoolean() }
.getOrElse(false)
buildTypes {
getByName("release") {
@@ -348,9 +371,9 @@ dependencies {
implementation(libs.zxing.embedded)
// Markdown
//implementation "com.halilibo.compose-richtext:richtext-ui:0.16.0"
//implementation "com.halilibo.compose-richtext:richtext-ui-material:0.16.0"
//implementation "com.halilibo.compose-richtext:richtext-commonmark:0.16.0"
// implementation "com.halilibo.compose-richtext:richtext-ui:0.16.0"
// implementation "com.halilibo.compose-richtext:richtext-ui-material:0.16.0"
// implementation "com.halilibo.compose-richtext:richtext-commonmark:0.16.0"
// Markdown (With fix for full-image bleeds)
implementation(libs.markdown.ui)
@@ -382,7 +405,7 @@ dependencies {
"playImplementation"(platform(libs.firebase.bom))
"playImplementation"(libs.firebase.messaging)
//PushNotifications(FDroid)
// PushNotifications(FDroid)
"fdroidImplementation"(libs.unifiedpush)
// Google Cast SDK — Chromecast support. Play flavor only because the
@@ -103,4 +103,4 @@
## Test Environment
- OS:
- JDK version:
- Amethyst version: 1.10.0 (feat/desktop-multi-account)
- Amethyst version: 1.11.0 (feat/desktop-multi-account)
@@ -41,7 +41,7 @@ data class RelayInfo(
const val NAME = "geode"
const val DESCRIPTION = "Embedded Nostr relay from the Amethyst quartz library."
const val SOFTWARE = "https://github.com/vitorpamplona/amethyst/tree/main/geode"
const val VERSION = "1.10.0"
const val VERSION = "1.11.0"
/**
* NIPs this relay implements out of the box. Single source of
+1 -1
View File
@@ -2,7 +2,7 @@
# Amethyst app version — single source of truth consumed by both Android (amethyst/)
# and Desktop (desktopApp/). Android versionCode is bumped independently in
# amethyst/build.gradle because it must be a monotonic integer.
app = "1.10.0"
app = "1.11.0"
accompanistAdaptive = "0.37.3"
cachemapVersion = "0.2.4"
composeMultiplatform = "1.11.0"
+1 -1
View File
@@ -370,7 +370,7 @@ mavenPublishing {
coordinates(
groupId = "com.vitorpamplona.quartz",
artifactId = "quartz",
version = "1.10.0",
version = "1.11.0",
)
// Configure publishing to Maven Central