131252f19d
- Rewrite build.gradle.kts for KMP with Android + JVM targets - Restructure source sets: commonMain, jvmAndroid, androidMain, jvmMain - Replace android.util.LruCache with androidx.collection.LruCache (KMP-ready) - Replace android.util.Patterns with local regex constants - Move shared code to commonMain (icons, hashtags, robohash, compose, etc.) - Move JVM-shared code to jvmAndroid (richtext, base64Image detection) - Keep Android-specific code in androidMain (blurhash, bitmap handling) - Remove @Preview annotations from shared code (Android-only feature) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
5.5 KiB
5.5 KiB
Amethyst Desktop Fork
Project Overview
Fork of Amethyst adding Compose Multiplatform Desktop support. Quartz library converted to full KMP for code sharing between Android and Desktop JVM.
Architecture
amethyst/
├── quartz/ # Nostr KMP library (protocol only, no UI)
│ └── src/
│ ├── commonMain/ # Shared Nostr protocol, data models
│ ├── androidMain/ # Android-specific (crypto, storage)
│ └── jvmMain/ # Desktop JVM-specific
├── commons/ # Shared UI components (convert to KMP)
│ └── src/
│ ├── commonMain/ # Shared composables, icons, state
│ ├── androidMain/ # Android-specific UI utilities
│ └── jvmMain/ # Desktop-specific UI utilities
├── desktopApp/ # Desktop JVM application (layouts, navigation)
├── amethyst/ # Android app (layouts, navigation)
└── ammolite/ # Support module
Sharing Philosophy:
quartz/= Business logic, protocol, data (no UI)commons/= Shared UI components, icons, composablesamethyst/&desktopApp/= Platform-native layouts and navigation
Tech Stack
| Layer | Technology |
|---|---|
| Core | Quartz (Nostr KMP) |
| UI | Compose Multiplatform 1.7.x |
| Async | kotlinx.coroutines + Flow |
| Network | OkHttp (JVM) |
| Serialization | Jackson |
| DI | Manual / Koin |
| Build | Gradle 8.x, Kotlin 2.1.0 |
Agents
Use these specialized agents for domain expertise:
| Agent | Expertise | When to Use |
|---|---|---|
nostr-protocol |
NIPs, events, relays, crypto | Protocol questions, NIP implementation |
kotlin-multiplatform |
KMP, source sets, expect/actual | Project structure, code sharing |
compose-ui |
Composables, Desktop features | UI components, navigation |
kotlin-coroutines |
Flows, async, concurrency | Data streams, async operations |
Commands
/desktop-run- Build and run desktop app/extract <component>- Move composable to shared code/nip <number>- Get NIP implementation guidance
Feature Workflow
When picking up a new task or feature, follow this process:
Step 1: Analyze Android Implementation
Start by examining the existing Android Amethyst codebase:
- Find the relevant feature/component in
amethyst/module - Understand the current implementation patterns
- Identify dependencies and integrations
Step 2: Create Implementation Plan
Before coding, create a plan that categorizes work into three buckets:
| Category | Description | Location |
|---|---|---|
| Android-Specific | Platform APIs, navigation, layouts | amethyst/, androidMain/ |
| Reusable (Shared) | Business logic, UI components, state | quartz/commonMain/, commons/ (convert to KMP) |
| Desktop-Specific | Desktop navigation, layouts, platform APIs | desktopApp/, jvmMain/ |
Step 3: Code Sharing Strategy
Share:
- Business logic and data models →
quartz/commonMain/ - Major UI components (cards, lists, dialogs) →
commons/(convert to KMP as needed) - State management and ViewModels → shared
- Icons and visual assets →
commons/commonMain/
Keep Platform-Native:
- Navigation patterns (sidebar vs bottom nav)
- Screen layouts and scaffolding
- Platform-specific interactions (gestures, keyboard shortcuts)
- System integrations (notifications, file pickers)
Step 4: Extract Shared Components
When extracting UI components:
- Identify reusable composables in Android code
- Use
/extract <component>to move tocommons/commonMain/ - Create expect/actual declarations for platform-specific behavior
- Update both Android and Desktop to use shared component
Note: quartz/ is protocol-only (no composables). Shared UI goes in commons/ after converting it to KMP.
Build Commands
# Run desktop app
./gradlew :desktopApp:run
# Run Android app
./gradlew :amethyst:installDebug
# Build Quartz for all targets
./gradlew :quartz:build
# Run tests
./gradlew test
# Format code
./gradlew spotlessApply
Quartz KMP Structure
The Quartz library uses expect/actual for platform-specific implementations:
// commonMain - shared protocol logic
expect class CryptoProvider {
fun sign(message: ByteArray, privateKey: ByteArray): ByteArray
fun verify(message: ByteArray, signature: ByteArray, publicKey: ByteArray): Boolean
}
// androidMain - uses secp256k1-kmp-jni-android
actual class CryptoProvider { /* Android implementation */ }
// jvmMain - uses secp256k1-kmp-jni-jvm
actual class CryptoProvider { /* JVM implementation */ }
Key Patterns
Platform Abstraction
// commonMain
expect fun openExternalUrl(url: String)
// androidMain
actual fun openExternalUrl(url: String) {
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
}
// jvmMain (Desktop)
actual fun openExternalUrl(url: String) {
Desktop.getDesktop().browse(URI(url))
}
Navigation Shell
- Desktop: Sidebar + main content area
- Android: Bottom navigation
Git Workflow
- Branch:
feat/desktop-<feature>orfix/desktop-<issue> - Commits: Conventional commits (
feat:,fix:, etc.) - Never use
--no-verify