A Kotlin Multiplatform skeleton with an Android app and an iOS app. The infrastructure is wired up; the feature is yours to build.
Rick and Morty API — public, no API key, no authentication.
Base URL: https://rickandmortyapi.com/api/
Two collections are relevant:
| Endpoint | List | Detail |
|---|---|---|
| Characters | GET /character?page={n} |
GET /character/{id} |
| Locations | GET /location?page={n} |
GET /location/{id} |
Both list endpoints are paginated and share the same envelope:
{
"info": { "count": 826, "pages": 42, "next": ".../character?page=2", "prev": null },
"results": [ { "id": 1, "name": "Rick Sanchez", "created": "2017-11-04T18:48:46.250Z", "...": "..." } ]
}Character and location objects have different shapes. Both carry a created timestamp.
- Paginate through both collections. Characters and locations are paged independently — page through each as the user scrolls.
- Show one mixed list. Characters and locations appear in a single list, interleaved by a
shared condition — for example
created— rather than grouped by type or concatenated. - Open a detail screen. Tapping an item loads it from its detail endpoint. A character and a location are not the same thing; the detail presentation should reflect that.
Handle loading, empty, and error states, and make paging behave on a slow or failing network.
:shared— Ktor client (base URL, JSON withignoreUnknownKeys, logging), Koin, Compose Multiplatform with type-safe Navigation, Coil for images, Kermit for logging, kotlinx-datetime.di/,data/,domain/,ui/are the intended homes for your code;appModuleindi/Koin.ktis where you register it.androidApp— renders the sharedApp()composable.iosApp— two tabs: Shared hosts the Compose Multiplatform UI from:shared, Native is an empty SwiftUI screen wired to the localRecNetworkingSwift package (URLSession +Codable, injected with Factory).- Unit-test dependencies (JUnit 5, MockK, coroutines-test, Ktor MockEngine) are declared. No tests are included.
- Compose Multiplatform or native. Implementing once in
commonMainis the default path. If SwiftUI is your strength, build the iOS side natively in the Native tab on top ofRecNetworkinginstead — the Android side stays Compose either way. Do one, not both. - Architecture, state handling, and libraries are up to you. Add dependencies to
gradle/libs.versions.toml(or Swift packages) if you want them.
- How you model a list of more than one type, and how the mixing rule is expressed.
- Pagination correctness: no duplicate or dropped items, no request storms, sane behaviour at the end of a collection.
- Separation between network, domain, and presentation, and whether the result is testable.
- Loading and error handling that a user would not be annoyed by.
- Readable, idiomatic code over feature volume.
Tests are welcome where they carry their weight — we would rather see a few meaningful ones than full coverage. Note anything you deliberately left out, and why.