CLAUDE.md
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
BlueMusic is an Android application that manages individual music and voice volumes for each Bluetooth device. The app is distributed on both GitHub (FOSS) and Google Play Store, with different build flavors for each platform.
Build Commands
# Build commands
./gradlew assembleFossDebug # FOSS debug build
./gradlew assembleGplayRelease # Google Play release build
./gradlew installFossDebug # Install FOSS debug on device
# Testing
./gradlew test # Run all unit tests
./gradlew testFossDebugUnitTest # Run FOSS debug unit tests
# Code quality
./gradlew lint # Run lint checks
./gradlew lintFix # Run lint with auto-fix
./gradlew ktlintCheck # Run ktlint checks (if configured)
./gradlew ktlintFormat # Run ktlint format (if configured)
Architecture
- Package by feature, not by layer
- Each feature package (if it has UI components and logic components), should have a
core
and aui
package. - Use Dagger/Hilt for dependency injection
- Repository pattern with Room (migrating from Realm) and DataStore
- UI that can be navigated to are “Screen”s and each screen has a corresponding ViewModel
- “Sub-screens” are called “Pages”
- The app uses Navigation3 (alpha) for Compose screens (
androidx.navigation3:navigation3-*
). - The main directions are inside the
Nav
file (common/navigation/Nav.kt
). - Each screen should have it’s own navigation entry providing class (extending
NavigationEntry
). - New classes should be injected if possible (using Dagger/Hilt)
- Classes should have a companion object with an appropriate
val TAG = logTag("toplevel","sublevel")
entry. - Use the Logging framework where appropriate to make future debugging easier (
Logging.kt
). - There are two different build flavors -
foss
(GitHub) andgplay
(Google Play with billing)
ViewModel Pattern
- Extend
BaseViewModel<State, Event>
(orViewModel1
throughViewModel4
variants) - Use
@HiltViewModel
annotation - State management via
StateFlow
- Events via
Channel<Event>
- Example:
class MyViewModel @Inject constructor(...) : BaseViewModel<MyState, MyEvent>()
Key Packages
eu.darken.bluemusic.bluetooth
: Bluetooth device discovery and managementeu.darken.bluemusic.devices
: Device management and UIeu.darken.bluemusic.main
: Main app navigation and settingseu.darken.bluemusic.common
: Shared utilities and base classeseu.darken.bluemusic.monitor
: Background monitoring and audio managementeu.darken.bluemusic.upgrade
: Premium features (flavor-specific)
Testing Approach
- Unit tests use JUnit, Mockk, and Kotest
- Hilt testing support is configured
- Test coverage is limited - add tests when modifying existing code
- Omit
androidTest
, we are not doing UI testing.
Agent instructions
- When localizing texts, create a TODO for each locale you need to provide translations for.
- Use sub-agents, one agent per TODO (if possible).
Code Style
- Kotlin-first codebase
- Use coroutines and Flow for async operations
- Follow existing patterns in the codebase
- Prefer immutable data classes for state
- When writing user facing texts, prefer informal and casual language.
- Use Hilt for dependency injection in new code
- Do NOT add comments on obvious code
- Prefer exposing fewer fields and functions and enabling specific functionality via extension functions
- All user facing strings should be extract to
values/strings.xml
and translated for all other languages too. @OptIn(ExperimentalMaterial3Api::class)
is not required- Create previews for all UI components using the
@Preview2
annotation andPreviewWrapper
- Prefer early returns to reduce code nesting
- Use
@Stable
and@Immutable
annotations where appropriate for Compose performance - Prefer
StateFlow
overLiveData
for new code - Use
collectAsStateWithLifecycle()
when collecting flows in Compose
Quick Reference
Key Files and Locations
- Main Activity:
app/src/main/java/eu/darken/bluemusic/main/ui/MainActivity.kt
- Application Class:
app/src/main/java/eu/darken/bluemusic/App.kt
- Navigation Routes:
app/src/main/java/eu/darken/bluemusic/common/navigation/Nav.kt
- String Resources:
- Common:
app/src/main/res/values*/strings.xml
(44+ locales) - FOSS flavor:
app/src/foss/res/values*/strings.xml
- Google Play flavor:
app/src/gplay/res/values*/strings.xml
- Common:
- Database (Room):
app/src/main/java/eu/darken/bluemusic/devices/core/database/DevicesRoomDb.kt
Common Base Classes
- ViewModels: Extend
BaseViewModel<State, Event>
fromcommon/architecture/
- Services: Extend
Service2
for lifecycle-aware services - Activities: Extend
Activity2
for common functionality - Compose Previews: Use
@Preview2
withPreviewWrapper
Error Handling
- Use
ErrorEventHandler
for UI error display - Throw
UserFacingException
for user-visible errors - All exceptions should have localizable messages
Permissions
- Bluetooth permissions are handled in
PermissionHelper
- Check permissions before Bluetooth operations
- Handle permission denial gracefully