6.3 KiB
Fluffytrix Agent Guidelines
Project Overview
Fluffytrix is an Android Matrix chat client with a Discord-like UI. Built with Kotlin, targeting Android 14+ (minSdk 34, targetSdk 36, compileSdk 36).
Package: com.example.fluffytrix
Build system: Gradle with Kotlin DSL, version catalog at gradle/libs.versions.toml
Container/DI: Koin
State management: Jetpack Compose StateFlow, ViewModel
UI framework: Jetpack Compose with Material 3 (Dynamic Colors)
Protocol: Trixnity SDK for Matrix
Storage: Room Database, DataStore Preferences
Async: Kotlin Coroutines
Build Commands
./gradlew assembleDebug # Build debug APK (minified for performance)
./gradlew assembleRelease # Build release APK
./gradlew test # Run unit tests
./gradlew connectedAndroidTest # Run instrumented tests on device/emulator
./gradlew testDebugUnitTest --tests "com.example.fluffytrix.ExampleUnitTest" # Run single test
Notes:
- Debug builds use R8 with
isDebuggable = truebut strip material-icons-extended and optimize Compose for performance - Use
--testswith Gradle test tasks to run a single test class - Instrumented tests require a connected device or emulator
Testing
Unit tests: Located in app/src/test/java/, run with ./gradlew test
Instrumented tests: Located in app/src/androidTest/java/, run with ./gradlew connectedAndroidTest
Single test execution:
./gradlew testDebugUnitTest --tests "com.example.fluffytrix.*"
./gradlew app:testDebugUnitTest --tests "ExampleUnitTest"
Code Style Guidelines
Kotlin Conventions
- Android Official Kotlin style (
kotlin.code.style=officialin gradle.properties) - File naming:
PascalCase.kt(e.g.,MainViewModel.kt) - Class naming:
PascalCase(e.g.,MainViewModel,AuthRepository) - Function/property naming:
camelCase(e.g.,sendMessage,selectedChannel) - Constant naming:
PascalCasefor top-level constants - Never use underscores in variable names
Imports
- Explicit imports only (no wildcard imports)
- Group imports: Android/X → Kotlin → Javax/Java → Third-party → Same package
- Example:
import android.os.Bundle import androidx.compose.material3.Text import kotlinx.coroutines.flow.StateFlow import net.folivo.trixnity.client.MatrixClient import com.example.fluffytrix.ui.theme.FluffytrixTheme
Types
- Prefer
valovervar(immutable data) - Use
StateFlow<T>for observable state in ViewModels - Use
Flow<T>for read-only data streams - Use
suspendfunctions for async operations - Use
Result<T>for operations that can fail
Error Handling
- Prefer
try-catchwith silent failure or?operators where appropriate - In ViewModels, use
catch (_: Exception) { }or?:for graceful degradation - Expose error state via
StateFlow<AuthState>where users need feedback - Never crash the app on recoverable errors
Compose UI
- Use
@Composablefor all UI functions - Follow Discord-like layout: space sidebar → channel list → message area → member list
- Use
MaterialThemefor consistent theming - Prefer
Modifier.padding()over nestedBoxwith margins - Use
wrapContentWidth()andfillMaxWidth()appropriately - For columnar layouts:
Column(horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(12.dp))
ViewModels
- Inject dependencies via constructor (Koin)
- Use
viewModelScopefor coroutines - Expose state via
StateFlow(e.g.,val messages: StateFlow<List<MessageItem>>) - Use
MutableStateFlowfor internal state, expose as read-onlyStateFlow
Coroutines
- Use
Dispatchers.Defaultfor CPU-intensive work (parsing, filtering) - Use
Dispatchers.IOfor file/network operations - Always cancel jobs on ViewModel cleanup:
job?.cancel() - Use
withContext(Dispatchers.Default)to switch threads explicitly
Data Layer
- Use Room for persistent storage (Trixnity uses Room internally)
- Use DataStore Preferences for small key-value data
- Prefer Flow-based APIs for reactive data streams
- Cache expensive operations in ViewModel (e.g.,
messageCache,memberCache)
Naming Conventions
- State Flow properties:
_name(private) /name(public) - Repository class:
AuthService,AuthRepository - ViewModel class:
MainViewModel,LoginViewModel - UI composable:
MainScreen,ChannelList,MessageItem - Model data class:
MessageItem,ChannelItem,SpaceItem - Use
fullproperty for Matrix IDs (e.g.,userId.full,roomId.full)
Architecture Patterns
Layered Architecture:
ui/ — ViewModels, Screens, Navigation
data/ — Repositories, local storage, models
di/ — Koin modules
ui/theme/ — Material 3 Theme (colors, typography)
Dependency Injection: Koin with two modules:
appModule: ViewModels (viewModel { MainViewModel(...) })dataModule: singleton services (single { AuthRepository(...) })
UI Flow:
FluffytrixNavigationhandles nav graph and session restorationMainActivityhosts the NavHost withFluffytrixTheme- ViewModels expose state via StateFlow
- Screens observe state with
collectAsState()
Key Dependencies (from libs.versions.toml)
- Compose BOM:
2025.06.00 - Kotlin:
2.2.10 - AGP:
9.0.1 - Koin:
4.1.1 - Trixnity:
4.22.7 - Ktor:
3.3.0 - Coroutines:
1.10.2 - DataStore:
1.1.7 - Coil:
3.2.0 - Media3:
1.6.0
Special Notes
-
Matrix IDs: Use
RoomId,UserIdtypes from Trixnity; access.fullfor string representation -
MXC URLs: Convert with
MxcUrlHelper.mxcToDownloadUrl()andmxcToThumbnailUrl() -
Build Performance: Debug builds use R8 minification with
isDebuggable = trueto balance speed and debuggability -
Channel Reordering: Channel order is saved per-space in DataStore and restored on navigation
-
Encrypted Rooms: Handle decryption state—messages may appear as
Unable to decryptuntil keys arrive -
Theme: Material 3 with Discord-inspired color scheme (primary:
#5865F2)
Running Lint/Checks
./gradlew lintDebug
./gradlew spotlessCheck
CI/CD
- All builds use Gradle wrapper (
./gradlew) - No manual Gradle installation required (project uses Gradle 9.1.0)