From db1c0def1a5b583c24f00d89b032bb8b324f4493 Mon Sep 17 00:00:00 2001 From: Fabian DEVEL Date: Mon, 30 Mar 2026 16:06:28 +0200 Subject: [PATCH 1/6] chore(Agents): Add AGENTS.md --- AGENTS.md | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..25f3e91fd4 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,149 @@ +# AGENTS.md - AI Context Brain + +## 1. 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 with push notifications (Google Play variant). + +### High-Level Tech Stack + +- **Language**: Kotlin (Java 17, JVM target 17) +- **Platform**: Android (minSdk 27, targetSdk 35, compileSdk 36) +- **Build System**: Gradle with Kotlin DSL (build.gradle.kts) +- **Architecture**: MVVM with Repository pattern, multi-module structure +- **Dependency Injection**: Dagger Hilt +- **Database**: Realm (RealmObject for models) +- **UI Framework**: Hybrid - Jetpack Compose + XML Views with ViewBinding +- **Network**: Retrofit/Ktor with Kotlin Serialization +- **Navigation**: Android Navigation Component with Safe Args +- **Crash Reporting**: Sentry +- **Analytics**: Matomo +- **CI/CD**: Fastlane + GitHub Actions +- **Testing**: JUnit 4, Espresso, UI Automator + +## 2. Context Map + +``` +android-kMail/ +├── app/ # Main application module +│ ├── src/main/java/com/infomaniak/mail/ # App source code +│ │ ├── MainApplication.kt # Application entry point +│ │ ├── MainActivity.kt # Main navigation coordinator (682 lines) +│ │ ├── data/ # Data layer (models, cache, API) +│ │ │ ├── cache/ # Realm database controllers +│ │ │ ├── models/ # Realm entities (Message, Thread, Draft, etc.) +│ │ │ └── api/ # API service interfaces +│ │ ├── di/ # Hilt dependency injection modules +│ │ ├── ui/ # UI layer (Activities, Fragments, ViewModels) +│ │ │ ├── main/ # Main mail UI (inbox, thread list, settings) +│ │ │ ├── newMessage/ # Compose new email flow +│ │ │ ├── login/ # Authentication flows +│ │ │ └── alertDialogs/ # Custom AlertDialog implementations +│ │ ├── utils/ # Utilities (formatters, extensions) +│ │ ├── workers/ # Background WorkManager workers +│ │ └── receivers/ # BroadcastReceivers (notifications) +│ ├── src/main/res/ # Android resources (layouts, drawables) +│ ├── src/main/res/navigation/ # Navigation graph XML files +│ ├── src/test/ # Unit tests (JUnit) +│ └── src/androidTest/ # UI/E2E tests (Espresso) +├── Core/ # Shared library modules +│ ├── Auth/ # Authentication logic +│ ├── Common/ # Shared utilities +│ ├── Network/ # Network layer abstractions +│ ├── Ui/ # Shared UI components +│ ├── Sentry/ # Sentry integration +│ ├── Matomo/ # Analytics integration +│ └── ... (30+ other specialized modules) +├── EmojiComponents/ # Custom emoji picker components +├── HtmlCleaner/ # HTML sanitization library +├── fastlane/ # Deployment automation +│ └── metadata/android/ # Play Store metadata +├── .github/workflows/ # CI/CD pipelines +├── build.gradle.kts # Root build configuration +├── settings.gradle.kts # Module definitions +└── gradle.properties # Gradle configuration +``` + +## 3. Local Norms + +### Architecture & Design + +- **MVVM Pattern**: Each screen has a Fragment/Activity + ViewModel +- **Repository Pattern**: Data access abstracted through controller classes (e.g., `ThreadController`) +- **Dependency Injection**: Use Hilt `@Inject` constructor for dependencies +- **Database**: All models extend `RealmObject` or `EmbeddedRealmObject` +- **SOLID**: Keep classes focused; MainActivity is currently 682 lines (do not grow further) +- **KISS**: Prefer simple solutions over complex architecture + +### Command Patterns + +```bash +# Build debug APK +./gradlew :app:assembleStandardDebug + +# Build release APK (requires env.properties with sentryAuthToken) +./gradlew :app:assembleStandardRelease + +# Run unit tests +./gradlew :app:testStandardDebugUnitTest + +# Run UI tests (requires device/emulator) +./gradlew :app:connectedStandardDebugAndroidTest + +# Clean build +./gradlew clean + +# Full project build +./gradlew build +``` + +### Code Style + +- **Kotlin Style**: Follow official Kotlin code style (`kotlin.code.style=official` in gradle.properties) +- **Naming**: + - Classes: PascalCase (e.g., `ThreadController`, `MainActivity`) + - Functions/Properties: camelCase (e.g., `getThreads()`, `isEmpty`) + - Packages: lowercase, single word (e.g., `com.infomaniak.mail.ui.main`) +- **File Naming**: Match class name exactly (e.g., `MainActivity.kt`) +- **Comments**: GPL license header in all source files + +### UI Development + +- **Hybrid Approach**: Use Compose for new screens, XML with ViewBinding for existing +- **Compose**: Use Material3 components, place composables in `com.infomaniak.mail.ui.components.compose` +- **XML Views**: Use ViewBinding (property access syntax), place in `com.infomaniak.mail.views` +- **Navigation**: Use Safe Args plugin for type-safe navigation between destinations + +### Testing + +- **Unit Tests**: Located in `app/src/test/java/` + - Use JUnit 4 with MockK for mocking + - Database tests use dummy datasets in `dataset/` package +- **UI Tests**: Located in `app/src/androidTest/java/` + - Use Espresso for view interactions + - Test files follow pattern: `*ActivityTest.kt` or `*Test.kt` +- **Test Flavors**: Separate test source sets for `standard` and `fdroid` flavors + +### Product Flavors + +- **standard**: Full-featured with Google Play Services (push notifications, Firebase) +- **fdroid**: FOSS variant without proprietary dependencies (no push notifications) +- Use `standardImplementation` or `fdroidImplementation` for flavor-specific dependencies + +### Environment Configuration + +- **env.properties**: Required for release builds (contains `sentryAuthToken`) +- **env.example.properties**: Template showing required properties +- **local.properties**: Local SDK paths (auto-generated by Android Studio) +- Never commit `env.properties` or `local.properties` (see .gitignore) + +### Learned Preferences + +- None yet - start recording here when the user corrects your assumptions. + +## 4. Self-correction + +This section is for you, the future agent. + +1. **Stale Map**: If you encounter a file or folder not listed in the "Context Map", update the map in this file. +2. **New Norms**: If the user corrects you (e.g., "Don't use X, use Y"), add that rule to the "Local norms" section immediately so you don't make the mistake again. +3. **Refinement**: If you find this file is too verbose, prune it. Keep it high-signal. From 204a3b3d68ce98995d062d70de157e041928dcc8 Mon Sep 17 00:00:00 2001 From: Fabian DEVEL Date: Tue, 31 Mar 2026 08:35:43 +0200 Subject: [PATCH 2/6] chore(Agents): Add some learned preferences --- AGENTS.md | 59 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 25f3e91fd4..a3c7dcb024 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,8 @@ ## 1. 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 with push notifications (Google Play variant). +**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 with push notifications (Google Play variant). ### High-Level Tech Stack @@ -99,10 +100,10 @@ android-kMail/ ### Code Style - **Kotlin Style**: Follow official Kotlin code style (`kotlin.code.style=official` in gradle.properties) -- **Naming**: - - Classes: PascalCase (e.g., `ThreadController`, `MainActivity`) - - Functions/Properties: camelCase (e.g., `getThreads()`, `isEmpty`) - - Packages: lowercase, single word (e.g., `com.infomaniak.mail.ui.main`) +- **Naming**: + - Classes: PascalCase (e.g., `ThreadController`, `MainActivity`) + - Functions/Properties: camelCase (e.g., `getThreads()`, `isEmpty`) + - Packages: lowercase, single word (e.g., `com.infomaniak.mail.ui.main`) - **File Naming**: Match class name exactly (e.g., `MainActivity.kt`) - **Comments**: GPL license header in all source files @@ -116,11 +117,11 @@ android-kMail/ ### Testing - **Unit Tests**: Located in `app/src/test/java/` - - Use JUnit 4 with MockK for mocking - - Database tests use dummy datasets in `dataset/` package + - Use JUnit 4 with MockK for mocking + - Database tests use dummy datasets in `dataset/` package - **UI Tests**: Located in `app/src/androidTest/java/` - - Use Espresso for view interactions - - Test files follow pattern: `*ActivityTest.kt` or `*Test.kt` + - Use Espresso for view interactions + - Test files follow pattern: `*ActivityTest.kt` or `*Test.kt` - **Test Flavors**: Separate test source sets for `standard` and `fdroid` flavors ### Product Flavors @@ -138,12 +139,48 @@ android-kMail/ ### Learned Preferences -- None yet - start recording here when the user corrects your assumptions. +When writing code, follow these specific style rules: + +**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 (helps identify happy path) + +**Copyright Headers:** + +- Required in ALL files (including resources) +- Format: `Copyright (C) YYYY` or `Copyright (C) startYear-endYear` +- No blank line between copyright and package declaration + +**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 + +**Enums:** + +- New enums: PascalCase entries (e.g., `Active`, `Inactive`) +- DO NOT rename existing enums (stored in sharedPrefs/Realm) ## 4. Self-correction This section is for you, the future agent. 1. **Stale Map**: If you encounter a file or folder not listed in the "Context Map", update the map in this file. -2. **New Norms**: If the user corrects you (e.g., "Don't use X, use Y"), add that rule to the "Local norms" section immediately so you don't make the mistake again. +2. **New Norms**: If the user corrects you (e.g., "Don't use X, use Y"), add that rule to the "Local norms" section immediately so + you don't make the mistake again. 3. **Refinement**: If you find this file is too verbose, prune it. Keep it high-signal. From 5b91a32708899565a02cb886cc0e95f840b5e724 Mon Sep 17 00:00:00 2001 From: Fabian DEVEL Date: Tue, 31 Mar 2026 10:14:45 +0200 Subject: [PATCH 3/6] chore(Agents): Add core agents.md --- AGENTS.md | 219 ++++++++++++-------------------------------------- Core | 2 +- app/AGENTS.md | 205 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 259 insertions(+), 167 deletions(-) create mode 100644 app/AGENTS.md diff --git a/AGENTS.md b/AGENTS.md index a3c7dcb024..940ff1378a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,186 +1,73 @@ -# AGENTS.md - AI Context Brain +# AGENTS.md - Infomaniak Mail (Top Level) -## 1. Project Summary +> **Navigation Guide**: This file describes the composite structure. For app-specific norms, see `app/AGENTS.md`. For Core library norms, see `Core/AGENTS.md`. -**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 with push notifications (Google Play variant). +## Repository Structure -### High-Level Tech Stack - -- **Language**: Kotlin (Java 17, JVM target 17) -- **Platform**: Android (minSdk 27, targetSdk 35, compileSdk 36) -- **Build System**: Gradle with Kotlin DSL (build.gradle.kts) -- **Architecture**: MVVM with Repository pattern, multi-module structure -- **Dependency Injection**: Dagger Hilt -- **Database**: Realm (RealmObject for models) -- **UI Framework**: Hybrid - Jetpack Compose + XML Views with ViewBinding -- **Network**: Retrofit/Ktor with Kotlin Serialization -- **Navigation**: Android Navigation Component with Safe Args -- **Crash Reporting**: Sentry -- **Analytics**: Matomo -- **CI/CD**: Fastlane + GitHub Actions -- **Testing**: JUnit 4, Espresso, UI Automator - -## 2. Context Map +This is a **composite Gradle build** with two main components: ``` android-kMail/ -├── app/ # Main application module -│ ├── src/main/java/com/infomaniak/mail/ # App source code -│ │ ├── MainApplication.kt # Application entry point -│ │ ├── MainActivity.kt # Main navigation coordinator (682 lines) -│ │ ├── data/ # Data layer (models, cache, API) -│ │ │ ├── cache/ # Realm database controllers -│ │ │ ├── models/ # Realm entities (Message, Thread, Draft, etc.) -│ │ │ └── api/ # API service interfaces -│ │ ├── di/ # Hilt dependency injection modules -│ │ ├── ui/ # UI layer (Activities, Fragments, ViewModels) -│ │ │ ├── main/ # Main mail UI (inbox, thread list, settings) -│ │ │ ├── newMessage/ # Compose new email flow -│ │ │ ├── login/ # Authentication flows -│ │ │ └── alertDialogs/ # Custom AlertDialog implementations -│ │ ├── utils/ # Utilities (formatters, extensions) -│ │ ├── workers/ # Background WorkManager workers -│ │ └── receivers/ # BroadcastReceivers (notifications) -│ ├── src/main/res/ # Android resources (layouts, drawables) -│ ├── src/main/res/navigation/ # Navigation graph XML files -│ ├── src/test/ # Unit tests (JUnit) -│ └── src/androidTest/ # UI/E2E tests (Espresso) -├── Core/ # Shared library modules -│ ├── Auth/ # Authentication logic -│ ├── Common/ # Shared utilities -│ ├── Network/ # Network layer abstractions -│ ├── Ui/ # Shared UI components -│ ├── Sentry/ # Sentry integration -│ ├── Matomo/ # Analytics integration -│ └── ... (30+ other specialized modules) -├── EmojiComponents/ # Custom emoji picker components -├── HtmlCleaner/ # HTML sanitization library -├── fastlane/ # Deployment automation -│ └── metadata/android/ # Play Store metadata -├── .github/workflows/ # CI/CD pipelines -├── build.gradle.kts # Root build configuration -├── settings.gradle.kts # Module definitions -└── gradle.properties # Gradle configuration +├── 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) ``` -## 3. Local Norms - -### Architecture & Design - -- **MVVM Pattern**: Each screen has a Fragment/Activity + ViewModel -- **Repository Pattern**: Data access abstracted through controller classes (e.g., `ThreadController`) -- **Dependency Injection**: Use Hilt `@Inject` constructor for dependencies -- **Database**: All models extend `RealmObject` or `EmbeddedRealmObject` -- **SOLID**: Keep classes focused; MainActivity is currently 682 lines (do not grow further) -- **KISS**: Prefer simple solutions over complex architecture - -### Command Patterns - -```bash -# Build debug APK -./gradlew :app:assembleStandardDebug - -# Build release APK (requires env.properties with sentryAuthToken) -./gradlew :app:assembleStandardRelease - -# Run unit tests -./gradlew :app:testStandardDebugUnitTest - -# Run UI tests (requires device/emulator) -./gradlew :app:connectedStandardDebugAndroidTest - -# Clean build -./gradlew clean - -# Full project build -./gradlew build -``` - -### Code Style - -- **Kotlin Style**: Follow official Kotlin code style (`kotlin.code.style=official` in gradle.properties) -- **Naming**: - - Classes: PascalCase (e.g., `ThreadController`, `MainActivity`) - - Functions/Properties: camelCase (e.g., `getThreads()`, `isEmpty`) - - Packages: lowercase, single word (e.g., `com.infomaniak.mail.ui.main`) -- **File Naming**: Match class name exactly (e.g., `MainActivity.kt`) -- **Comments**: GPL license header in all source files - -### UI Development +## Quick Summary -- **Hybrid Approach**: Use Compose for new screens, XML with ViewBinding for existing -- **Compose**: Use Material3 components, place composables in `com.infomaniak.mail.ui.components.compose` -- **XML Views**: Use ViewBinding (property access syntax), place in `com.infomaniak.mail.views` -- **Navigation**: Use Safe Args plugin for type-safe navigation between destinations +| 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 | -### Testing +## Composite Build Explained -- **Unit Tests**: Located in `app/src/test/java/` - - Use JUnit 4 with MockK for mocking - - Database tests use dummy datasets in `dataset/` package -- **UI Tests**: Located in `app/src/androidTest/java/` - - Use Espresso for view interactions - - Test files follow pattern: `*ActivityTest.kt` or `*Test.kt` -- **Test Flavors**: Separate test source sets for `standard` and `fdroid` flavors +- **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! -### Product Flavors +## Key Integration Points -- **standard**: Full-featured with Google Play Services (push notifications, Firebase) -- **fdroid**: FOSS variant without proprietary dependencies (no push notifications) -- Use `standardImplementation` or `fdroidImplementation` for flavor-specific dependencies +- **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**: `InfomaniakCore.init()` must be called in `MainApplication.kt` -### Environment Configuration +## Quick Commands -- **env.properties**: Required for release builds (contains `sentryAuthToken`) -- **env.example.properties**: Template showing required properties -- **local.properties**: Local SDK paths (auto-generated by Android Studio) -- Never commit `env.properties` or `local.properties` (see .gitignore) - -### Learned Preferences - -When writing code, follow these specific style rules: - -**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 (helps identify happy path) - -**Copyright Headers:** - -- Required in ALL files (including resources) -- Format: `Copyright (C) YYYY` or `Copyright (C) startYear-endYear` -- No blank line between copyright and package declaration - -**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 +```bash +# Build Mail app +./gradlew :app:assembleStandardDebug -**Enums:** +# Build Core library only +./gradlew Core:assemble -- New enums: PascalCase entries (e.g., `Active`, `Inactive`) -- DO NOT rename existing enums (stored in sharedPrefs/Realm) +# Run all tests +./gradlew :app:testStandardDebugUnitTest && ./gradlew Core:test -## 4. Self-correction +# Lint Core (uses ktlint in Core module) +./gradlew Core:ktlintCheck +``` -This section is for you, the future agent. +## Important Rules -1. **Stale Map**: If you encounter a file or folder not listed in the "Context Map", update the map in this file. -2. **New Norms**: If the user corrects you (e.g., "Don't use X, use Y"), add that rule to the "Local norms" section immediately so - you don't make the mistake again. -3. **Refinement**: If you find this file is too verbose, prune it. Keep it high-signal. +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..cb1906e88b 160000 --- a/Core +++ b/Core @@ -1 +1 @@ -Subproject commit ed19d52c8b4710062c4c4e85e5518ed2d34dbb40 +Subproject commit cb1906e88b992363c1d783c41ca63b6e7566e2df diff --git a/app/AGENTS.md b/app/AGENTS.md new file mode 100644 index 0000000000..a537691263 --- /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 (Java 17, JVM target 17) +- **Platform**: Android (minSdk 27, targetSdk 35, compileSdk 36) +- **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, must call InfomaniakCore.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; MainActivity is already 682 lines + +### 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 From abd6eb801239b80d97156500c272fa3100424912 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 06:03:34 +0000 Subject: [PATCH 4/6] chore(Agents): Replace hardcoded SDK versions with build.gradle.kts references, generalize SOLID principle Agent-Logs-Url: https://github.com/Infomaniak/android-kMail/sessions/79d61e2a-7ee3-4bed-9032-11ade3a9d344 Co-authored-by: FabianDevel <45429131+FabianDevel@users.noreply.github.com> --- app/AGENTS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/AGENTS.md b/app/AGENTS.md index a537691263..5aa1cd9778 100644 --- a/app/AGENTS.md +++ b/app/AGENTS.md @@ -9,8 +9,8 @@ Compose, Realm database, and multi-account support. ### High-Level Tech Stack -- **Language**: Kotlin (Java 17, JVM target 17) -- **Platform**: Android (minSdk 27, targetSdk 35, compileSdk 36) +- **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 @@ -59,7 +59,7 @@ app/src/androidTest/ # Espresso UI tests - **Repository**: Data access via controllers (`ThreadController`, `DraftController`) - **DI**: Use Hilt `@Inject` constructor - **Database**: Models extend `RealmObject` or `EmbeddedRealmObject` -- **SOLID/KISS**: Keep classes focused; MainActivity is already 682 lines +- **SOLID/KISS**: Keep classes focused; prefer multiple smaller classes over one large class ### Commands From f04033a594e3d5999f8eaa293850a6367146544e Mon Sep 17 00:00:00 2001 From: Fabian DEVEL Date: Thu, 23 Apr 2026 09:08:29 +0200 Subject: [PATCH 5/6] chore: Bump core --- Core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core b/Core index cb1906e88b..f27df54de7 160000 --- a/Core +++ b/Core @@ -1 +1 @@ -Subproject commit cb1906e88b992363c1d783c41ca63b6e7566e2df +Subproject commit f27df54de783941ac59ea624d35dd67154e3d1d0 From 53ecc5a8ab0053f5362a79ffb090437d8c3bf0fe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 09:17:01 +0000 Subject: [PATCH 6/6] chore(Agents): Fix incorrect init references and Gradle task paths in AGENTS.md files Agent-Logs-Url: https://github.com/Infomaniak/android-kMail/sessions/b428b9cd-4de7-45a5-9c92-b0f35c0da982 Co-authored-by: FabianDevel <45429131+FabianDevel@users.noreply.github.com> --- AGENTS.md | 14 +++++++------- app/AGENTS.md | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 940ff1378a..eb15d854ed 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,7 +11,7 @@ android-kMail/ ├── Core/ # Git submodule - shared library (see Core/AGENTS.md) │ ├── Auth/ # OAuth2, account management │ ├── Network/ # Ktor HTTP client -│ ├── Ui/ # Compose + XML components +│ ├── Ui/ # Compose + XML components │ ├── Common/ # Shared utilities │ └── ... (30+ modules) ├── app/ # Main Mail application (see app/AGENTS.md) @@ -43,7 +43,7 @@ android-kMail/ - **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**: `InfomaniakCore.init()` must be called in `MainApplication.kt` +- **Initialization**: `MainApplication.kt` initializes Core via `NetworkConfiguration.init()` and `AuthConfiguration.init()` inside `configureInfomaniakCore()` ## Quick Commands @@ -51,14 +51,14 @@ android-kMail/ # Build Mail app ./gradlew :app:assembleStandardDebug -# Build Core library only -./gradlew Core:assemble +# Build included Core modules +./gradlew :Core:Legacy:assemble :Core:Legacy:Confetti:assemble # Run all tests -./gradlew :app:testStandardDebugUnitTest && ./gradlew Core:test +./gradlew :app:testStandardDebugUnitTest && ./gradlew :Core:Legacy:test :Core:Legacy:Confetti:test -# Lint Core (uses ktlint in Core module) -./gradlew Core:ktlintCheck +# Lint included Core modules (uses ktlint) +./gradlew :Core:Legacy:ktlintCheck :Core:Legacy:Confetti:ktlintCheck ``` ## Important Rules diff --git a/app/AGENTS.md b/app/AGENTS.md index 5aa1cd9778..63fa78a95d 100644 --- a/app/AGENTS.md +++ b/app/AGENTS.md @@ -25,7 +25,7 @@ Compose, Realm database, and multi-account support. ``` app/src/main/java/com/infomaniak/mail/ -├── MainApplication.kt # Entry point, must call InfomaniakCore.init() +├── 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.)