checkNotInMainThread was a debug-only Android assertion (Looper check behind BuildConfig.DEBUG). Once the cache, feeds and view models moved to commons it could only fire through the LocalCacheHost.assertNotMainThread hook, which is a no-op on every other front end, so it no longer guarded the shared code it was sprinkled through. The checker, its call sites and the host hook are removed; the two comments that explained a Dispatchers.IO switch by the assertion now give the real reason (compression blocks). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S7FuNBSKiyVecARSoE4B9P
3.9 KiB
Common Utility Functions
Canonical helpers that repeatedly come up when working in Amethyst. Prefer these to hand-rolling equivalents.
Formatting (commons)
All under commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/:
NumberFormatters.ktcountToHumanReadable(counter: Int, noun: String): String—1500 → "1K items",2_500_000 → "2M items". SuffixesK,M,G.countToHumanReadableBytes(bytes: Int): String—1024 → "1 KB", scales through KB/MB/GB/TB.
PubKeyFormatter.kt— condense an npub tonpub1abc…xyzwith a symmetric prefix/suffix truncation. Use in chips and small UI that show an author.EmojiUtils.kt— parse custom emoji (:name:), render bridging to NIP-30emojitags.IterableUtils.kt— small shortcuts likefirstNotNullOfvariants, chunking helpers.PlatformNumberFormatter.kt— expect/actual locale-aware number formatting (delegates toNumberFormaton JVM/Android).
Time (quartz)
quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/TimeUtils.kt — the source of truth for "now in Nostr seconds" and common offsets:
TimeUtils.now() // Long seconds since epoch (Nostr `created_at`)
TimeUtils.oneMinuteAgo()
TimeUtils.fiveMinutesAgo()
TimeUtils.fifteenMinutesAgo()
TimeUtils.oneHourAgo()
TimeUtils.oneDayAgo()
TimeUtils.oneWeekAgo()
TimeUtils.withinTenMinutes(other) // |now - other| < 10m
Constants (TEN_SECONDS, ONE_MINUTE, FIVE_MINUTES, TEN_MINUTES, FIFTEEN_MINUTES, ONE_HOUR, EIGHT_HOURS, ONE_DAY, ONE_WEEK) are in seconds and are what every subscription filter and staleness check uses — keep using them instead of magic numbers.
Hex / bytes / strings (quartz)
Under quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/:
Hex.kt—ByteArray.toHex(),String.hexToByteArray(). MPP-friendly, no java.util.StringUtils.kt— generic helpers (normalization, truncation).StringExt.kt— small extensions (e.g. safe substring).UriParser.kt— NIP-19 / nostr URI friendly URL parsing without java.net.UrlEncoder.kt/Rfc3986.kt— percent-encoding / decoding for URL-safe content.UnicodeNormalizer.kt— NFC normalization for search/matching.
Threading & coroutines
commons/src/commonMain/.../threading/Threading.kt— shared dispatchers andCoroutineScopehelpers for commonMain code.amethyst/src/main/java/.../service/CoroutinesExt.kt— Android-only helpers:launchIO(block),launchMain(block)built on top ofDispatchers.IO/Dispatchers.Main. Use these in ViewModels and services to stop re-spelling the dispatcher every time.
Quartz iterables & JSON
quartz/.../utils/IterableExt.kt— mutation-free filter/map/group helpers used by the cache layer.quartz/.../utils/JsonElementExt.kt— safe navigation for Jackson nodes when parsing unknown-shape JSON.quartz/.../kotlinSerialization/OptimizedJsonMapper.kt— shared Jackson mapper with reifiedfromJson<T>(...)/toJson(...); prefer this to spinning up a localObjectMapper.
Number formatting for Android display
amethyst/src/main/java/.../service/CountFormatter.kt and ByteFormatter.kt wrap the commons formatters with Android-specific pluralization / locale. Use them from Android UI; use the commons functions directly from commonMain.
When to Add vs Reuse
Before introducing a new helper:
grep -r "fun count\|fun format\|fun toHuman" commons/ quartz/— there is almost certainly something already.- If you're about to write
System.currentTimeMillis() / 1000— useTimeUtils.now(). - If you're about to write
String.format("%.1f K", n / 1000.0)— usecountToHumanReadable. - If you need locale-specific rendering on both Android and Desktop, reach for
PlatformNumberFormatter(expect/actual) rather than hard-coding.