This file provides guidance to WARP (warp.dev) when working with code in this repository.
RoundTimer is a Kotlin Multiplatform (KMP) board game timer application targeting Android, iOS, Desktop (JVM), and Web (WASM) platforms. It uses Compose Multiplatform for the UI layer and follows a clean architecture pattern with ViewModel state management.
# Desktop (JVM) - Primary development target
./gradlew :composeApp:run
# Android debug build
./gradlew :composeApp:assembleDebug
# Web (WASM) - Modern browsers
./gradlew :composeApp:wasmJsBrowserDevelopmentRun
# Web (JS) - Legacy browser support
./gradlew :composeApp:jsBrowserDevelopmentRun
# iOS - Open iosApp in Xcode or use IDE run configuration# Run common tests
./gradlew :composeApp:testCommonUnitTest
# Run all tests
./gradlew test# Android release (requires signing config)
./gradlew :composeApp:assembleRelease
# Desktop distributables
./gradlew :composeApp:createDistributable/composeApp/src/commonMain/kotlin/- Shared business logic and UI/composeApp/src/androidMain/kotlin/- Android-specific implementations/composeApp/src/jvmMain/kotlin/- Desktop-specific implementations/composeApp/src/iosMain/kotlin/- iOS-specific implementations/composeApp/src/wasmJsMain/kotlin/- Web WASM implementations/buildSrc/- Custom Gradle build logic including Git versioning
State Management: Uses TimerViewModel with StateFlow for reactive state management. The app has a single source of truth in TimerState data class.
Platform Abstraction: Platform-specific functionality is abstracted through expect/actual declarations:
SoundPlayer- Audio playback across platformsScreenLocker- Prevents screen sleep during timerPlatformStorage- Data persistence (DataStore on Android, UserDefaults on iOS)AnalyticsService- Event tracking with Firebase on Android
Navigation: Simple screen-based navigation using sealed classes and Crossfade animations. No complex navigation library - just state-driven screen switching.
Audio System: Complex audio cue system with different drum sounds based on remaining time:
- 60s, 50s, 40s: Single call sound
- 36s, 19s: Intense sound
- 0s and overtime: Overtime sound
Data Models:
TimerState- Main app state containerRound- Individual timer session recordGame- Group of rounds with date and nameAudioCue- Audio configuration for timer thresholds
App.kt- Main app composition and screen routingTimerViewModel.kt- Core business logic and state managementTimerState.kt- App state data model- Platform-specific
SoundPlayerimplementations for audio handling - Storage implementations for data persistence
- Coroutines: Heavy use of coroutines for timer operations and storage I/O
- Compose: Modern declarative UI with Material 3 design system
- State Hoisting: UI components receive state and callbacks, no local state
- Platform Types: Expect/actual pattern for platform-specific functionality
- Error Handling: Graceful degradation for storage and audio failures
- Uses Gradle version catalogs (
gradle/libs.versions.toml) - Custom Git versioning in
buildSrc/GitVersioning.kt - Firebase integration for Android analytics
- Hot reload enabled for development
Currently minimal test coverage. When adding tests:
- Unit tests go in
commonTestfor shared logic - Platform tests in respective
{platform}Testdirectories - Focus on
TimerViewModelbusiness logic and utility functions
- Android: Uses DataStore for persistence, Firebase Analytics, system dark mode detection
- Desktop: Custom macOS dark mode detection, Swing coroutines integration
- iOS: AVFoundation framework linking for audio, UserDefaults storage
- Web: Limited audio capabilities, localStorage for persistence