Imported from martinrevert/LaTorrentola (
AGENTS.md). Install upstream withnpx skills add martinrevert/LaTorrentola. Copyright stays with the author.
AGENTS.md — Quick onboarding for AI coding agents
Checklist for this agent run:
- Understand app architecture and DI boundaries
- Note project-specific serialization / DB / networking patterns
- List dev workflows (build/install) and gotchas
- Point to concrete files to inspect for changes
- Implement unit and UI tests for core components
Short summary
- This is a Jetpack Compose + Hilt Android app (Kotlin). Core patterns: Retrofit (Gson), Room, kotlinx.serialization on models, coroutines + Flow, and androidx.navigation3 runtime for navigation keys. Authentication is handled via Firebase + Google Sign-in (Credential Manager).
Essential places to read first
- App entry and navigation:
app/src/main/java/com/martinrevert/latorrentola/MainActivity.ktandui/navigation/AppNavigation.kt(deep-link via Intent extra "PELI"; navigation transfers Movie as JSON using kotlinx.serialization). Navigation also handles auth-gating (Route.Login vs Route.Home). - Authentication & Cloud Sync:
network/AuthRepository.kt,network/UserLibraryRepository.kt(Firestore),ui/auth/AuthViewModel.kt,ui/auth/LoginScreen.kt, anddi/AuthModule.kt. Sensitive credentials likeWEB_CLIENT_IDare injected vialocal.properties. - Network & DI:
di/NetworkModule.kt,network/YtsService.kt,network/YtsRepository.kt(Retrofit service + repository that mixes remote + Firestore sync). - Models & persistence:
model/YTS/*(e.g.Movie.kt) anddatabase/Converters.kt. Local persistence (Room) is reserved for session data (GenreStats, LastVisit); Favorites and Downloads are synced via Firestore. - Build and dependency versions:
gradle/libs.versions.tomlandapp/build.gradle(KSP, Hilt, Google services plugins; git-based versionCode) - Firebase / Google services:
google-services.json(project and app-level copies) andapp/keys/release.keystore(release signing asset)
Project-specific patterns and gotchas (do not assume defaults)
- Mixed serialization: Models have both
kotlinx.serialization(@Serializable) and Gson@SerializedName. Retrofit is configured withGsonConverterFactory. - Cloud-First Persistence: Favorites and Download history are stored in Firebase Firestore (keyed by Google UID). Room is only used for local analytics and session metadata. Do not add new entities to Room if they need to persist across devices.
- Navigation transfers entire Movie objects as JSON strings via
Json.encodeToString(Movie.serializer(), movie)andJson.decodeFromString(...)inAppNavigation.kt. Keep serializers in sync with model changes. - Translation & UI Utilities:
utils/UiText.ktcontains theGenreTranslationobject, which is the single source of truth for mapping API genre strings to localizedUiTextresources. Use this in all screens (Home, Search, Details) to maintain consistency. - Multi-Selection Pattern: The
SearchScreen(favorites view) implements a selection mode for D-pad compatibility. Short-press navigates to details, long-press enters selection mode. Once in selection mode, short-press toggles selection. - Credential Safety: Never hardcode API keys or Web Client IDs. Use
local.propertieswith a correspondingbuildConfigFieldinapp/build.gradle. Reference them viaBuildConfig. - DI scope: Hilt is used for singletons (see
di/NetworkModule.kt). When adding bindings, follow the@Module @InstallIn(SingletonComponent::class)pattern. - Theme and Readability: Always respect the app's themes. Ensure all UI changes are compatible with both light and dark modes without losing human readability. Avoid hardcoding colors like
Color.BlackorColor.Whiteunless they are specifically meant to be static; instead, useMaterialTheme.colorSchemetokens. Be careful with imports to avoid shadowing standard Material3 components with TV-specific ones that might have different default behaviors. - Adaptive UI & Multi-Device Support: The app is designed for phones, tablets, foldables, and Android TV.
- Device Detection: Use
Context.isTvDevice()(fromDeviceUtils.kt) for TV-specific logic. - Wide Screens: Use
LocalConfiguration.current.screenWidthDp >= 600(often referred to asisWideScreen) to detect tablets and foldables in landscape. - Layout Differences: TVs and wide screens use side-by-side layouts (e.g., in
MovieDetailScreenandSettingsScreen) and larger grid column counts. - Input Handling: TVs require D-pad focus handling. Use
Modifier.focusHighlight(),focusRestorer(), and avoid touch-only interactions likePullToRefreshon TV. - Previews: Every screen MUST have multiple
@Previewfunctions:PreviewLightDarkfor mobile (light/dark) and*TvPreviewwithuiModevariations for TV (light/dark).
- Device Detection: Use
- Git-based versionCode:
app/build.gradlerunsgit rev-list --count HEADto setversionCode/versionName. Ensure git is present in CI or on developer machines when producing builds.
Common tasks & exact commands (Windows PowerShell)
- Clean & build debug APK:
.
\gradlew.bat clean; .\gradlew.bat assembleDebug
- Install debug APK to a connected device:
.\gradlew.bat installDebug
# then start app via adb (package + launcher activity)
adb shell am start -n com.martinrevert.latorrentola/.MainActivity
- Run all unit tests:
.\gradlew.bat testDebugUnitTest
- Run instrumented (UI) tests:
.\gradlew.bat connectedDebugAndroidTest
- Generate JaCoCo coverage report:
.\gradlew.bat testDebugUnitTest jacocoTestReport
- Build release (signed) APK / AAB (ensure
app/keys/release.keystoreis present and signing config is set in Gradle):
.\gradlew.bat assembleRelease
.\gradlew.bat bundleRelease
Important files to update when changing behavior
- Networking:
network/YtsService.kt+di/NetworkModule.kt(Retrofit client and logging interceptor) - Authentication & Sync:
network/AuthRepository.kt,network/UserLibraryRepository.ktandui/auth/* - Data layer:
network/YtsRepository.kt(combines remote + local flows) anddatabase/*(DAO/Converters) - UI routing:
ui/navigation/AppNavigation.kt(how Movie JSON is passed and auth-gating) and top-level Composables underui/*
Integration points & external dependencies
- YTS API: base URL defined in
constants/Constants.kt(Constants.YTS_BASE_URL) - Firebase: Auth (Google Sign-in), Crashlytics, and Messaging.
google-services.jsonmust be valid and SHA-1 registered in Firebase Console for Google Sign-in. - ML Kit Translate: used for on-device translations (dependency in gradle BOM)
- YouTube player library for trailers (dependency present in libs)
Testing / CI notes
- Modern unit tests are located in
app/src/test/java. They use MockK, Turbine, and Truth. - Instrumented UI tests are located in
app/src/androidTest/java. They usecreateComposeRule()and Hilt. - Instrumented tests use a custom runner:
com.martinrevert.latorrentola.HiltTestRunner. - MockK Android (
mockk-android) is included for instrumented test mocking. - When testing ViewModels, use
MainDispatcherRule(underrules/) to mockDispatchers.Main. - The project forces a modern version of
byte-buddy(1.18.15+) and usesorg.gradle.jvmargsingradle.propertiesto avoidsun.misc.Unsafewarnings across all build tasks (compilation and testing) on modern JDKs. - JaCoCo is configured (v0.8.15) with broad exclusions for ByteBuddy/MockK proxy classes to prevent instrumentation errors on newer JDKs.
- CI should run
./gradlew testDebugUnitTestto verify logic and optionallyconnectedDebugAndroidTestfor UI. - If adding new testable components, follow the existing patterns in
YtsRepositoryTest,HomeViewModelTest, orHomeUiTest. - CI must have
gitavailable (versionCode uses commit count) and Android SDK + buildtools matching AGP settings (gradle/libs.versions.toml).
If you edit models:
- Update
@SerializableKotlin serializers and add@SerializedNamefor any field used by Retrofit/Room converters. - Update
database/Converters.ktif new nested/collection types are persisted.
Quick pointers for PR reviewers (what to check)
- Serialization symmetry: ensure new model fields are present in both kotlinx and Gson annotations
- DI scopes: prefer
@SingletoninNetworkModule-style modules unless intentionally scoped narrower - Navigation payload size: passing full Movie JSON is convenient but can grow; consider passing ID and fetching details if payload becomes large
End of agent guide — keep this file in root as the single-source quick reference for code-modifying agents.