# Development
## Notes on development methodology
**This project was completely vibe-coded**, 100%, with the help of Claude Code and Opus 4.5. There it is, I said it, the shame is now gone.
I am/was pretty skeptical on LLM-generated code and this was born as an experiment to learn how it actually was to *vibe-code* something from scratch.
Turns out it's pretty awesome and easy to follow the happy path for a stock, modern Android app which just displays data consumed from a JSON REST API.
I'm a DevOps guy and I have zero mobile development skills, so achieving this can be considered pretty awesome in my book. But I'm pretty sure in the eyes of a skilled Kotlin Android developer, this code might induce different feelings.
At the moment, I completely depend on CC to maintain the app, but I would like to take this opportunity as an excuse to learn more about the Android development ecosystem, beside learning how to tame an LLM agent.
### Project Structure
```
matedroid/
├── app/src/main/java/com/matedroid/
│ ├── data/ # Data layer (API, repository, local storage)
│ ├── domain/ # Domain layer (models, use cases)
│ ├── ui/ # UI layer (screens, components, theme)
│ └── di/ # Dependency injection modules
├── gradle/ # Gradle wrapper and version catalog
├── util/ # Utility scripts
├── ASSETS.md # Tesla car image asset documentation
└── PLAN.md # Detailed implementation plan
```
### Tech Stack
- **Language**: Kotlin
- **UI**: Jetpack Compose with Material Design 3
- **Architecture**: MVVM + Clean Architecture
- **DI**: Hilt
- **Networking**: Retrofit + OkHttp + Moshi
- **Local Storage**: DataStore
- **Charts**: Vico
- **Maps**: osmdroid (OpenStreetMap)
### Localization (i18n)
The app supports multiple languages using Android's standard resource-based localization system. Currently supported languages:
- **English** (default) - `res/values/strings.xml`
- **Italian** - `res/values-it/strings.xml`
- **Spanish** - `res/values-es/strings.xml`
- **Catalan** - `res/values-ca/strings.xml`
#### Adding/Modifying Translations
1. **All user-visible strings must be in string resources** - never hardcode text in Kotlin files
2. **String naming convention**: Use `snake_case` (e.g., `settings_title`, `drive_history`)
3. **Add context comments** for translators above each string:
```xml
Select Vehicle
```
#### Adding a New String
1. Add the English string to `res/values/strings.xml`:
```xml
Feature Name
```
2. Add translations to all locale files:
- `res/values-it/strings.xml`
- `res/values-es/strings.xml`
- `res/values-ca/strings.xml`
3. Use in Kotlin code:
```kotlin
import androidx.compose.ui.res.stringResource
import com.matedroid.R
Text(text = stringResource(R.string.new_feature_label))
```
#### Format Strings
For strings with dynamic values, use placeholders:
```xml
Limit: %d%%
Since %1$s (%2$d days ago)
```
Usage:
```kotlin
stringResource(R.string.charge_limit_format, chargeLimit)
stringResource(R.string.avg_year_message, formattedDate, dayCount)
```
#### Adding a New Language
1. Create a new folder: `res/values-{language_code}/`
2. Copy `res/values/strings.xml` to the new folder
3. Translate all strings, keeping the same `name` attributes
4. Android will automatically use the correct language based on device settings
#### Testing Translations
Change your device/emulator language in Settings > System > Languages to test different locales.
### Utility Scripts
#### `util/fetch_tesla_assets.py`
Python script to download Tesla car 3D renders from Tesla's compositor service. Requires [uv](https://github.com/astral-sh/uv) for dependency management.
```bash
# Download all car images (Model 3 & Y, various colors/wheels)
./util/fetch_tesla_assets.py
# Preview what would be downloaded
./util/fetch_tesla_assets.py --dry-run
# Custom output directory
./util/fetch_tesla_assets.py --output-dir /path/to/assets
```
See [ASSETS.md](ASSETS.md) for detailed documentation on Tesla compositor APIs, color/wheel code mappings, and troubleshooting.
### Running Tests
```bash
# Unit tests
./gradlew test
# Instrumented tests (requires emulator/device)
./gradlew connectedAndroidTest
```
### Releasing
Releases are automated via GitHub Actions. When a release is published, the workflow builds the APK and attaches it to the release.
```bash
# 1. Update version in app/build.gradle.kts (versionCode and versionName)
# 2. Update CHANGELOG.md with release notes
# 3. Commit and push
# 4. Create a release with GitHub CLI
gh release create v0.5.0 --generate-notes
# Or create a draft release to edit notes first
gh release create v0.5.0 --generate-notes --draft
```
#### Signing Configuration (Optional)
For release signing with a custom keystore, set these repository secrets:
- `KEYSTORE_BASE64`: Base64-encoded keystore file (`base64 -w0 your.keystore`)
- `KEYSTORE_PASSWORD`: Keystore password
- `KEY_ALIAS`: Key alias
- `KEY_PASSWORD`: Key password
Without secrets, the APK is signed with a debug keystore (fine for sideloading, not for Play Store).
### Development Workflow
1. Start your Android emulator or connect a device
2. Build and install: `make install`
3. View logs: `adb logcat | grep -i matedroid`
#### Makefile Targets
| Target | Description |
|----------------|-------------------------------------------------|
| `make build` | Build debug APK |
| `make install` | Build and install debug APK on connected device |
| `make run` | Build, install, and launch the app |
| `make clean` | Clean build artifacts |
| `make test` | Run unit tests |
Or use Android Studio:
1. Open the project folder
2. Wait for Gradle sync
3. Click Run (green play button)
## Configuration
On first launch, you'll be prompted to configure your TeslamateApi connection:
1. **Server URL**: Your TeslamateApi instance URL (e.g., `https://teslamate-api.example.com`)
2. **API Token**: (Optional) If your instance requires authentication