{"id":50330300,"url":"https://github.com/tarek-bohdima/dogsapp","last_synced_at":"2026-05-29T09:02:34.594Z","repository":{"id":307759689,"uuid":"813830649","full_name":"Tarek-Bohdima/DogsApp","owner":"Tarek-Bohdima","description":"Android Kotlin sample: random dog photos with offline-first Room cache and favorites. Modern stack — KSP, Coil 3, kotlinx.serialization, StateFlow, Hilt, AGP 9.","archived":false,"fork":false,"pushed_at":"2026-05-10T21:23:10.000Z","size":16233,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-05-10T21:24:56.462Z","etag":null,"topics":["android","coil","coroutines","dog-ceo-api","flow","hilt","kotlin","kotlinx-serialization","ksp","mvvm-architecture","navigation-component","offline-first","recyclerview","retrofit2","room","stateflow","swipetorefresh","viewbinding","viewmodel"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Tarek-Bohdima.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-06-11T20:35:13.000Z","updated_at":"2026-05-10T21:23:14.000Z","dependencies_parsed_at":"2025-08-02T03:46:24.798Z","dependency_job_id":"708606a0-1ba9-4235-898b-d1e241cde383","html_url":"https://github.com/Tarek-Bohdima/DogsApp","commit_stats":null,"previous_names":["tarek-bohdima/dogsapp"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Tarek-Bohdima/DogsApp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tarek-Bohdima%2FDogsApp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tarek-Bohdima%2FDogsApp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tarek-Bohdima%2FDogsApp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tarek-Bohdima%2FDogsApp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Tarek-Bohdima","download_url":"https://codeload.github.com/Tarek-Bohdima/DogsApp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tarek-Bohdima%2FDogsApp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33644313,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","coil","coroutines","dog-ceo-api","flow","hilt","kotlin","kotlinx-serialization","ksp","mvvm-architecture","navigation-component","offline-first","recyclerview","retrofit2","room","stateflow","swipetorefresh","viewbinding","viewmodel"],"created_at":"2026-05-29T09:02:29.137Z","updated_at":"2026-05-29T09:02:34.581Z","avatar_url":"https://github.com/Tarek-Bohdima.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DogsApp\n\n[![Android CI](https://github.com/Tarek-Bohdima/DogsApp/actions/workflows/build_pull_request.yml/badge.svg?branch=master)](https://github.com/Tarek-Bohdima/DogsApp/actions/workflows/build_pull_request.yml)\n[![Platform](https://img.shields.io/badge/platform-Android-3DDC84?logo=android\u0026logoColor=white)](https://developer.android.com)\n[![Kotlin](https://img.shields.io/badge/Kotlin-2.3.21-7F52FF?logo=kotlin\u0026logoColor=white)](https://kotlinlang.org)\n[![Java](https://img.shields.io/badge/Java-17-007396?logo=openjdk\u0026logoColor=white)](https://openjdk.org/projects/jdk/17/)\n[![AGP](https://img.shields.io/badge/AGP-9.2.0-3DDC84)](https://developer.android.com/build/releases/gradle-plugin)\n[![minSdk](https://img.shields.io/badge/minSdk-26-blue)](app/build.gradle)\n[![targetSdk](https://img.shields.io/badge/targetSdk-36-blue)](app/build.gradle)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\nA small Android sample app that fetches and displays random dog photos from the public [dog.ceo](https://dog.ceo/dog-api/) API. Built as a modern Android playground: KSP-only annotation processing, Coil 3, kotlinx.serialization, Room with Flow, and StateFlow-driven ViewModels.\n\n## Screenshots\n\n| Main grid | Dog details | Offline (cached) |\n| --- | --- | --- |\n| \u003cimg src=\"docs/screenshots/main.png\" alt=\"Main grid of random dog photos\" width=\"240\"/\u003e | \u003cimg src=\"docs/screenshots/details.png\" alt=\"Dog details screen showing breed\" width=\"240\"/\u003e | \u003cimg src=\"docs/screenshots/offline.png\" alt=\"Cached dog list served from Room while offline\" width=\"240\"/\u003e |\n\nThe offline panel is captured with Wi-Fi and mobile data disabled and the app force-stopped: Room serves the cached list and Coil serves the previously-loaded images from its disk cache, while the status icon signals the failed refresh.\n\n### Favorites flow\n\n| Details (not favorited) | Details (favorited) | Favorites screen |\n| --- | --- | --- |\n| \u003cimg src=\"docs/screenshots/fav_details_empty.png\" alt=\"Dog details screen with the heart toggle in its empty state\" width=\"240\"/\u003e | \u003cimg src=\"docs/screenshots/fav_details_filled.png\" alt=\"Dog details screen with the heart toggle filled in\" width=\"240\"/\u003e | \u003cimg src=\"docs/screenshots/fav_screen.png\" alt=\"Favorites screen showing the dogs the user has hearted\" width=\"240\"/\u003e |\n\n## Features\n\n- Grid of random dog images, refreshable via swipe-to-refresh\n- Tap a dog to open a details screen\n- Offline-first: cached list + image cache survive process death and no network\n- Favorite individual dogs from the details screen and browse them on a Favorites screen\n- Network layer with Retrofit + kotlinx.serialization\n- Local persistence with Room exposing Flow\n- Dependency injection with Hilt (KSP, no Kapt)\n- StateFlow-driven `ViewModel`s collected via `repeatOnLifecycle`\n- Navigation Component with Safe Args\n- View Binding (no Data Binding XML expressions)\n\n## Tech stack\n\n| Area              | Library                                            |\n| ----------------- | -------------------------------------------------- |\n| Language          | Kotlin 2.3.21, bytecode target JVM 17              |\n| Build             | Android Gradle Plugin 9.2.0, Gradle 9.4.1 (daemon JDK 21) |\n| Annotation proc.  | KSP 2.3.7 (no Kapt)                                |\n| UI                | View system + View Binding, Material 1.13.0        |\n| Architecture      | MVVM (ViewModel + StateFlow)                       |\n| DI                | Hilt 2.59.2                                        |\n| Persistence       | Room 2.8.4 (offline cache + favorites, Flow APIs)  |\n| Networking        | Retrofit 2.11.0, kotlinx.serialization 1.11.0      |\n| Async             | Kotlin Coroutines 1.11.0                           |\n| Image loading     | Coil 3.4.0 (with `coil-network-okhttp`)            |\n| Navigation        | AndroidX Navigation 2.9.8 (Safe Args)              |\n| Lifecycle         | androidx.lifecycle 2.10.0                          |\n| Refresh           | `SwipeRefreshLayout` 1.1.0                         |\n\n## Project structure\n\n```\napp/src/main/java/com/example/android/dogsapp\n├── common\n│   ├── di/application      # Hilt module (Retrofit, Room, repository, image loader, refresh manager)\n│   └── imaging             # ImageLoader interface + CoilImageLoader\n├── data\n│   ├── domain              # Dog (+ displayBreedName helper), DogsResponse\n│   ├── network             # DogsApi (Retrofit interface)\n│   ├── local               # Room: DogEntity, FavoriteEntity, DAOs, DogsDatabase, MIGRATION_1_2\n│   └── repository          # DogsRepository (interface) + impl\n└── ui\n    ├── main                # MainFragment, MainViewModel, DogsAdapter\n    ├── details             # DetailsFragment, DetailsViewModel\n    ├── favorites           # FavoritesFragment, FavoritesViewModel\n    └── utils               # RefreshManager / SwipeToRefreshManagerImpl\n```\n\n## Getting started\n\n### Requirements\n\n- Android Studio (Ladybug or newer recommended)\n- JDK 21 (the Gradle daemon is pinned to 21 via `gradle/gradle-daemon-jvm.properties`; Gradle will auto-provision it via Foojay if you don't have it locally). App bytecode target is still JVM 17.\n- Android SDK with API level 36 installed\n\n### Build \u0026 run\n\n```bash\ngit clone https://github.com/Tarek-Bohdima/DogsApp.git\ncd DogsApp\n./gradlew assembleDebug\n```\n\nThen open the project in Android Studio and run the `app` configuration on an emulator or device (API 26+).\n\n### Tests\n\n```bash\n./gradlew test\n```\n\n## Continuous Integration\n\nEvery pull request against `master` runs the [`Android CI`](.github/workflows/build_pull_request.yml) workflow on `ubuntu-latest`: it sets up JDK 21 (matching the Gradle daemon pin), caches Gradle, builds a debug APK, and runs unit tests.\n\n## Documentation\n\n- [ARCHITECTURE.md](ARCHITECTURE.md) — how the layers fit together, why we picked each piece of the stack.\n- [CONTRIBUTING.md](CONTRIBUTING.md) — branch/PR/squash workflow, conventions, how to add a feature, PR checklist.\n- [CLAUDE.md](CLAUDE.md) — onboarding for Claude Code agents working in this repo.\n\n## Credits\n\nDog images provided by the free [Dog CEO API](https://dog.ceo/dog-api/).\n\n## License\n\nReleased under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftarek-bohdima%2Fdogsapp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftarek-bohdima%2Fdogsapp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftarek-bohdima%2Fdogsapp/lists"}