diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..eb15d854ed --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,73 @@ +# AGENTS.md - Infomaniak Mail (Top Level) + +> **Navigation Guide**: This file describes the composite structure. For app-specific norms, see `app/AGENTS.md`. For Core library norms, see `Core/AGENTS.md`. + +## Repository Structure + +This is a **composite Gradle build** with two main components: + +``` +android-kMail/ +├── Core/ # Git submodule - shared library (see Core/AGENTS.md) +│ ├── Auth/ # OAuth2, account management +│ ├── Network/ # Ktor HTTP client +│ ├── Ui/ # Compose + XML components +│ ├── Common/ # Shared utilities +│ └── ... (30+ modules) +├── app/ # Main Mail application (see app/AGENTS.md) +│ ├── src/main/java/... # Mail app source code +│ ├── src/main/res/ # Android resources +│ ├── src/test/ # Unit tests +│ └── src/androidTest/ # UI tests +├── EmojiComponents/ # Custom emoji picker +├── HtmlCleaner/ # HTML sanitization +└── AGENTS.md # This file (top-level overview) +``` + +## Quick Summary + +| Component | Location | AGENTS.md | Purpose | +|-----------|----------|-----------|---------| +| **Core** | `Core/` | `Core/AGENTS.md` | Reusable library for all Infomaniak apps | +| **App** | `app/` | `app/AGENTS.md` | Mail app-specific code and norms | +| **Root** | `./` | `AGENTS.md` | This file - composite build overview | + +## Composite Build Explained + +- **Core is a Git submodule**: Changes in `Core/` are tracked separately and shared with other Infomaniak apps +- **Immediate resolution**: App uses `com.infomaniak.core:` which resolves locally (no Maven publishing needed) +- **Impact**: Changes to Core affect ALL Infomaniak apps - be careful! + +## Key Integration Points + +- **Authentication**: App uses `Core:Auth` for OAuth2 (tokens, account management) +- **Networking**: App uses `Core:Network` with `HttpClientProvider` from `Core:Common` +- **UI Components**: App uses `Core:Ui:Compose` and `Core:Ui:View` components +- **Initialization**: `MainApplication.kt` initializes Core via `NetworkConfiguration.init()` and `AuthConfiguration.init()` inside `configureInfomaniakCore()` + +## Quick Commands + +```bash +# Build Mail app +./gradlew :app:assembleStandardDebug + +# Build included Core modules +./gradlew :Core:Legacy:assemble :Core:Legacy:Confetti:assemble + +# Run all tests +./gradlew :app:testStandardDebugUnitTest && ./gradlew :Core:Legacy:test :Core:Legacy:Confetti:test + +# Lint included Core modules (uses ktlint) +./gradlew :Core:Legacy:ktlintCheck :Core:Legacy:Confetti:ktlintCheck +``` + +## Important Rules + +1. **Editing Core**: Core changes affect ALL apps - consider impact carefully +2. **Norm separation**: + - App norms → `app/AGENTS.md` + - Core norms → `Core/AGENTS.md` + - Composite structure → this file +3. **When working on:** + - `app/src/...` → read `app/AGENTS.md` + - `Core/` → read `Core/AGENTS.md` \ No newline at end of file diff --git a/Core b/Core index ed19d52c8b..f27df54de7 160000 --- a/Core +++ b/Core @@ -1 +1 @@ -Subproject commit ed19d52c8b4710062c4c4e85e5518ed2d34dbb40 +Subproject commit f27df54de783941ac59ea624d35dd67154e3d1d0 diff --git a/app/AGENTS.md b/app/AGENTS.md new file mode 100644 index 0000000000..63fa78a95d --- /dev/null +++ b/app/AGENTS.md @@ -0,0 +1,205 @@ +# AGENTS.md - Infomaniak Mail App + +> For the Core library, see `Core/AGENTS.md`. For composite build overview, see root `AGENTS.md`. + +## Project Summary + +**Infomaniak Mail** is an Android email client application built by Infomaniak Network SA, featuring a modern UI with Jetpack +Compose, Realm database, and multi-account support. + +### High-Level Tech Stack + +- **Language**: Kotlin — JVM target set via `javaVersion` in `build.gradle.kts` +- **Platform**: Android — SDK versions (`appMinSdk`, `appTargetSdk`, `appCompileSdk`) set in `build.gradle.kts` +- **Build System**: Gradle with Kotlin DSL +- **Architecture**: MVVM with Repository pattern +- **Dependency Injection**: Dagger Hilt +- **Database**: Realm (RealmObject for models) +- **UI Framework**: Hybrid - Jetpack Compose + XML Views with ViewBinding +- **Network**: Ktor with Kotlin Serialization +- **Navigation**: Android Navigation Component with Safe Args +- **Crash Reporting**: Sentry +- **Analytics**: Matomo + +## Context Map + +``` +app/src/main/java/com/infomaniak/mail/ +├── MainApplication.kt # Entry point, configures core via configureInfomaniakCore() (NetworkConfiguration.init() / AuthConfiguration.init()) +├── MainActivity.kt # Main coordinator (682 lines - keep focused) +├── data/ # Data layer +│ ├── cache/ # Realm controllers (ThreadController, etc.) +│ ├── models/ # Realm entities (Message, Thread, Draft, Mailbox, etc.) +│ └── api/ # API service interfaces +├── di/ # Hilt modules +├── ui/ # UI layer +│ ├── main/ # Inbox, thread list, settings +│ ├── newMessage/ # Compose new email flow +│ ├── login/ # Authentication flows +│ └── alertDialogs/ # Custom dialogs +├── utils/ # Utilities and extensions +├── workers/ # WorkManager background tasks +└── receivers/ # BroadcastReceivers (notifications) + +app/src/main/res/ +├── layout/ # XML layouts (ViewBinding) +├── navigation/ # Navigation graphs +├── drawable/ # Vector drawables +└── ... # Other resources + +app/src/test/ # JUnit unit tests +app/src/androidTest/ # Espresso UI tests +``` + +## Local Norms + +### Architecture & Design + +- **MVVM**: Fragment/Activity + ViewModel per screen +- **Repository**: Data access via controllers (`ThreadController`, `DraftController`) +- **DI**: Use Hilt `@Inject` constructor +- **Database**: Models extend `RealmObject` or `EmbeddedRealmObject` +- **SOLID/KISS**: Keep classes focused; prefer multiple smaller classes over one large class + +### Commands + +```bash +# Build debug +./gradlew :app:assembleStandardDebug + +# Build release (requires env.properties with sentryAuthToken) +./gradlew :app:assembleStandardRelease + +# Run tests +./gradlew :app:testStandardDebugUnitTest +./gradlew :app:connectedStandardDebugAndroidTest # UI tests need device + +# Clean +./gradlew clean +``` + +### Code Style + +**Line Length:** + +- Maximum **130 characters** per line for Kotlin files +- Exceptions: single-line comments, import statements, hardcoded strings + +**Blank Lines:** + +- Never use more than 1 consecutive blank line +- Always add 1 blank line after early return statements/blocks + +**Copyright Headers:** + +- Required in ALL files (including resources) +- Format: `Copyright (C) YYYY` or `Copyright (C) startYear-endYear` +- Example: `(C) 2022-2026 Infomaniak Network SA` +- **No blank line between copyright and package declaration** + +**Naming:** + +- Classes: PascalCase (`MainActivity`, `ThreadController`) +- Functions/Properties: camelCase (`getThreads()`, `isEmpty`) +- Packages: lowercase (`com.infomaniak.mail.ui.main`) +- **New enums**: PascalCase entries (`Active`, `Inactive`) +- **Old enums**: DO NOT rename (stored in sharedPrefs/Realm - would break) + +**Control Flow:** + +```kotlin +// Trivial statements: prefer one-line (under 130 chars) +if (condition) return result + +// Trivial if/else: prefer one-line +val color = if (isDark) darkColor else lightColor + +// Non-trivial: always use braces + newlines +if (condition) { + doSomething() + doAnotherThing() +} +``` + +**Jetpack Compose:** + +```kotlin +// One parameter: one line (if under 130 chars) +@Composable +fun MyButton(onClick: () -> Unit) { + Text("Click") +} + +// Multiple parameters: standard formatting with proper indent +@Composable +fun MyButton( + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + // implementation +} +``` + +**Resources (XML):** + +- Remove `fillColor="#00000000"` (invisible colors auto-added by Figma) +- Follow Android Studio formatting conventions +- Use Android Studio's Reformat Code on drawable/ files + +**Kotlin Files:** + +- Follow official Kotlin code style (`kotlin.code.style=official` in gradle.properties) +- GPL license headers required + +### UI Development + +- **Hybrid Approach**: Compose for new screens, XML with ViewBinding for existing +- **Compose**: Material3 components, place in `ui.components.compose` +- **XML**: ViewBinding with property access syntax, place in `views` +- **Navigation**: Use Safe Args plugin for type-safe navigation + +### Testing + +- **Unit Tests**: `app/src/test/java/` + - JUnit 4 + MockK for mocking + - Use dummy datasets in `dataset/` package for database tests +- **UI Tests**: `app/src/androidTest/java/` + - Espresso for view interactions + - Pattern: `*ActivityTest.kt` or `*Test.kt` + +### Product Flavors + +| Flavor | Description | Dependencies | +|--------------|---------------------------------------------------------|--------------------------| +| **standard** | Full features, Google Play Services, push notifications | `standardImplementation` | +| **fdroid** | FOSS variant, no proprietary dependencies | `fdroidImplementation` | + +### Environment + +- `env.properties`: Required for release builds (sentryAuthToken) +- `local.properties`: Local SDK paths (auto-generated) +- Never commit `env.properties` or `local.properties` (see .gitignore) + +## Learned Preferences + +*Add project-specific corrections here as they occur.* + +**Kotlin Control Flow:** + +- Prefer one-line if/else for trivial statements under 130 chars +- Always use braces + newlines for non-trivial statements + +**Jetpack Compose:** + +- One-line composables with single parameter (within line limit) + +**Resources (XML):** + +- Remove fillColor="#00000000" (invisible colors from Figma imports) +- Follow Android Studio formatting on PRs if formatting is off + +## Self-correction + +1. **Stale Map**: Update when you encounter new files/folders not listed +2. **New Norms**: Add user corrections to "Learned Preferences" immediately +3. **Reference Core**: When editing Core imports, check `Core/AGENTS.md` for Core-specific norms