Files
fluffytrix/AGENTS.md
2026-02-22 01:26:41 +00:00

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 = true but strip material-icons-extended and optimize Compose for performance
  • Use --tests with 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=official in 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: PascalCase for 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 val over var (immutable data)
  • Use StateFlow<T> for observable state in ViewModels
  • Use Flow<T> for read-only data streams
  • Use suspend functions for async operations
  • Use Result<T> for operations that can fail

Error Handling

  • Prefer try-catch with 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 @Composable for all UI functions
  • Follow Discord-like layout: space sidebar → channel list → message area → member list
  • Use MaterialTheme for consistent theming
  • Prefer Modifier.padding() over nested Box with margins
  • Use wrapContentWidth() and fillMaxWidth() appropriately
  • For columnar layouts: Column(horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(12.dp))

ViewModels

  • Inject dependencies via constructor (Koin)
  • Use viewModelScope for coroutines
  • Expose state via StateFlow (e.g., val messages: StateFlow<List<MessageItem>>)
  • Use MutableStateFlow for internal state, expose as read-only StateFlow

Coroutines

  • Use Dispatchers.Default for CPU-intensive work (parsing, filtering)
  • Use Dispatchers.IO for 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 full property 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:

  1. FluffytrixNavigation handles nav graph and session restoration
  2. MainActivity hosts the NavHost with FluffytrixTheme
  3. ViewModels expose state via StateFlow
  4. 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

  1. Matrix IDs: Use RoomId, UserId types from Trixnity; access .full for string representation

  2. MXC URLs: Convert with MxcUrlHelper.mxcToDownloadUrl() and mxcToThumbnailUrl()

  3. Build Performance: Debug builds use R8 minification with isDebuggable = true to balance speed and debuggability

  4. Channel Reordering: Channel order is saved per-space in DataStore and restored on navigation

  5. Encrypted Rooms: Handle decryption state—messages may appear as Unable to decrypt until keys arrive

  6. 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)