{"id":13428920,"url":"https://github.com/igorwojda/android-showcase","last_synced_at":"2025-05-13T15:09:03.667Z","repository":{"id":37458209,"uuid":"158460787","full_name":"igorwojda/android-showcase","owner":"igorwojda","description":"💎 Android application following best practices:  Kotlin, Coroutines, JetPack, Clean Architecture, Feature Modules, Tests, MVVM, DI, Static Analysis...","archived":false,"fork":false,"pushed_at":"2025-05-08T03:38:33.000Z","size":9993,"stargazers_count":6605,"open_issues_count":17,"forks_count":900,"subscribers_count":119,"default_branch":"main","last_synced_at":"2025-05-08T04:32:26.678Z","etag":null,"topics":["android","android-application","architecture","best-practices","clean-architecture","gradle","jetpack","kotlin","kotlin-coroutines","mvvm"],"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/igorwojda.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":"CODE_OF_CONDUCT.md","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":"2018-11-20T22:45:04.000Z","updated_at":"2025-05-08T03:38:35.000Z","dependencies_parsed_at":"2023-10-05T01:42:32.116Z","dependency_job_id":"bd00d3e8-171c-43a5-8fba-6550fd94a20b","html_url":"https://github.com/igorwojda/android-showcase","commit_stats":{"total_commits":847,"total_committers":24,"mean_commits":"35.291666666666664","dds":"0.31641086186540734","last_synced_commit":"50f3126b6c610f98299b19f5d9a960fb6395134b"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorwojda%2Fandroid-showcase","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorwojda%2Fandroid-showcase/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorwojda%2Fandroid-showcase/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorwojda%2Fandroid-showcase/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/igorwojda","download_url":"https://codeload.github.com/igorwojda/android-showcase/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253969238,"owners_count":21992262,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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","android-application","architecture","best-practices","clean-architecture","gradle","jetpack","kotlin","kotlin-coroutines","mvvm"],"created_at":"2024-07-31T01:01:08.818Z","updated_at":"2025-05-13T15:08:58.655Z","avatar_url":"https://github.com/igorwojda.png","language":"Kotlin","readme":"# 💎 Android Showcase 2.0\n\n[![Kotlin Version](https://img.shields.io/badge/Kotlin-1.9.x-blue.svg)](https://kotlinlang.org)\n[![AGP](https://img.shields.io/badge/AGP-8.x-blue?style=flat)](https://developer.android.com/studio/releases/gradle-plugin)\n[![Gradle](https://img.shields.io/badge/Gradle-8.x-blue?style=flat)](https://gradle.org)\n\n[![Codebeat Badge](https://codebeat.co/badges/e9f1a825-b5bd-4c7a-aadc-7c8d0cf59310)](https://codebeat.co/projects/github-com-igorwojda-android-showcase-main)\n[![CodeFactor](https://www.codefactor.io/repository/github/igorwojda/android-showcase/badge)](https://www.codefactor.io/repository/github/igorwojda/android-showcase)\n\nThe Android Showcase project exemplifies modern [Android](https://en.wikipedia.org/wiki/Android_(operating_system)) application development methodologies and provides comprehensive architectural guidance. By integrating popular development tools, libraries, linters, and Gradle plugins, along with robust testing frameworks and Continuous Integration (CI) setup, this project offers a holistic sample of a fully operational Android application.\n\nThe primary focus of this project lies in promoting a modular, scalable, maintainable, and testable [architecture](#architecture). It incorporates a leading-edge [tech-stack](#tech-stack) and embodies the finest practices in software development. While the application may appear straightforward, it encompasses all the crucial components that lay the groundwork for a robust, large-scale application.\n\nThe design principles and architectural choices applied in this project are ideally suited for larger teams and extended [application lifecycles](https://en.wikipedia.org/wiki/Application_lifecycle_management). This application is not just about showcasing functionalities, but it is also a testament to how well-structured and well-written code serves as a stable backbone for scalable and maintainable software development projects.\n\n- [💎 Android Showcase 2.0](#-android-showcase-20)\n  - [Application Scope](#application-scope)\n  - [Tech-Stack](#tech-stack)\n  - [Architecture](#architecture)\n    - [Module Types And Module Dependencies](#module-types-and-module-dependencies)\n    - [Feature Module Structure](#feature-module-structure)\n      - [Presentation Layer](#presentation-layer)\n      - [Domain Layer](#domain-layer)\n      - [Data Layer](#data-layer)\n    - [Data Flow](#data-flow)\n  - [Dependency Management](#dependency-management)\n  - [Logcat debugging](#logcat-debugging)\n  - [CI Pipeline](#ci-pipeline)\n    - [Pull Request Verification](#pull-request-verification)\n  - [Design Decisions](#design-decisions)\n  - [What This Project Does Not Cover?](#what-this-project-does-not-cover)\n  - [Getting Started](#getting-started)\n    - [Android Studio](#android-studio)\n    - [Command-line And Android Studio](#command-line-and-android-studio)\n    - [Plugins](#plugins)\n  - [Upcoming Improvements](#upcoming-improvements)\n  - [Inspiration](#inspiration)\n    - [Cheatsheet](#cheatsheet)\n    - [Android Projects](#android-projects)\n  - [Known Issues](#known-issues)\n  - [Contribute](#contribute)\n  - [Author](#author)\n  - [License](#license)\n  - [Animations License](#animations-license)\n\n## Application Scope\n\nThe android-showcase is a simple application that presents information about various music albums. This data is dynamically sourced from the [Last.fm](https://www.last.fm/api)  music platform API.\n\nThe app has a few screens located in multiple feature modules:\n\n- Album list screen - displays list of albums\n- Album detail screen - display information about the selected album\n- Profile screen - empty (WiP)\n- Favourites screen - empty (WiP)\n  \u003cbr/\u003e\u003cbr/\u003e\n\n\u003cp\u003e\n  \u003cimg src=\"misc/image/screen_album_list.webp\" width=\"250\" /\u003e\n  \u003cimg src=\"misc/image/screen_album_detail.webp\" width=\"250\" /\u003e\n  \u003cimg src=\"misc/image/screen_favorites.webp\" width=\"250\" /\u003e\n\u003c/p\u003e\n\n## Tech-Stack\n\nThis project takes advantage of best practices and many popular libraries and tools in the Android ecosystem. Most of\nthe libraries are in the stable version unless there is a good reason to use non-stable version of the dependency.\n\n* Tech-stack\n  * [100% Kotlin](https://kotlinlang.org/)\n    + [Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) - perform background operations\n    + [Kotlin Flow](https://kotlinlang.org/docs/flow.html) - data flow across all app layers, including views\n    + [Kotlin Symbol Processing](https://kotlinlang.org/docs/ksp-overview.html) - enable compiler plugins\n    + [Kotlin Serialization](https://kotlinlang.org/docs/serialization.html) - parse [JSON](https://www.json.org/json-en.html)\n  * [Retrofit](https://square.github.io/retrofit/) - networking\n  * [Jetpack](https://developer.android.com/jetpack)\n    * [Compose](https://developer.android.com/jetpack/compose) - modern, native UI kit\n    * [Navigation](https://developer.android.com/topic/libraries/architecture/navigation/) - in-app navigation\n    * [Lifecycle](https://developer.android.com/topic/libraries/architecture/lifecycle) - perform an action when\n      lifecycle state changes\n    * [ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel) - store and manage UI-related\n      data in a lifecycle-aware way\n    * [Room](https://developer.android.com/jetpack/androidx/releases/room) - store offline cache\n  * [Koin](https://insert-koin.io/) - dependency injection (dependency retrieval)\n  * [Coil](https://github.com/coil-kt/coil) - image loading library\n  * [Lottie](http://airbnb.io/lottie) - animation library\n* Modern Architecture\n  * [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)\n  * Single activity architecture\n    using [Navigation component](https://developer.android.com/guide/navigation/navigation-getting-started)\n  * MVVM + MVI (presentation layer)\n  * [Android Architecture components](https://developer.android.com/topic/libraries/architecture)\n    ([ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel)\n    , [Kotlin Flow](https://kotlinlang.org/docs/flow.html)\n    , [Navigation](https://developer.android.com/jetpack/androidx/releases/navigation))\n  * [Android KTX](https://developer.android.com/kotlin/ktx) - Jetpack Kotlin extensions\n* UI\n  * Reactive UI\n  * [Jetpack Compose](https://developer.android.com/jetpack/compose) - modern, native UI kit (used for Fragments)\n  * [View Binding](https://developer.android.com/topic/libraries/view-binding) - retrieve XML view ids\n    (used for [NavHostActivity](app/src/main/java/com/igorwojda/showcase/app/presentation/NavHostActivity.kt) only)\n  * [Material Design 3](https://m3.material.io/) - application design system providing UI components\n  * Theme selection\n    * [Dark Theme](https://material.io/develop/android/theming/dark) - dark theme for the app (Android 10+)\n    * [Dynamic Theming](https://m3.material.io/styles/color/dynamic-color/overview) - use generated, wallpaper-based\n      theme (Android 12+)\n* CI\n  * [GitHub Actions](https://github.com/features/actions)\n  * Automatic PR verification including tests, linters, and 3rd online tools\n* Testing\n  * [Konsist](https://docs.konsist.lemonappdev.com/) via ([JUnit 5](https://junit.org/junit5/)\n  * [Unit Tests](https://en.wikipedia.org/wiki/Unit_testing) via ([JUnit 5](https://junit.org/junit5/)\n    [android-junit5](https://github.com/mannodermaus/android-junit5)) - test individual classes\n  * [Konsist](https://docs.konsist.lemonappdev.com/) - test code conventions and architectural rules\n  * [UI Tests](https://en.wikipedia.org/wiki/Graphical_user_interface_testing) ([Espresso](https://developer.android.com/training/testing/espresso)) -\n    test user interface (WiP)\n  * [Mockk](https://mockk.io/) - mocking framework\n  * [Kluent](https://github.com/MarkusAmshove/Kluent) - assertion framework\n* Static analysis tools (linters)\n  * [Ktlint](https://github.com/pinterest/ktlint) - verify code formatting\n  * [Detekt](https://github.com/arturbosch/detekt#with-gradle) - verify code complexity and code smells\n  * [Android Lint](http://tools.android.com/tips/lint) - verify Android platform usage\n* Gradle\n  * [Gradle Kotlin DSL](https://docs.gradle.org/current/userguide/kotlin_dsl.html) - define build scripts\n  * Custom tasks\n  * [Gradle Plugins](https://plugins.gradle.org/)\n    * [Android Gradle](https://developer.android.com/studio/releases/gradle-plugin) - standard Android Plugins\n    * [Test Logger](https://github.com/radarsh/gradle-test-logger-plugin) - format test logs\n    * [SafeArgs](https://developer.android.com/guide/navigation/navigation-pass-data#Safe-args) - pass data between\n      navigation destinations\n    * [Android-junit5](https://github.com/mannodermaus/android-junit5) - use [JUnit 5](https://junit.org/junit5/) with Android\n  * [Versions catalog](https://docs.gradle.org/current/userguide/platforms.html#sub:version-catalog) - define dependencies\n  * [Type safe accessors](https://docs.gradle.org/7.0/release-notes.html)\n* GitHub Boots\n  * [Renovate](https://github.com/renovatebot/renovate) - automatically update dependencies\n  * [Stale](https://github.com/marketplace/stale) - automatically closes stale Issues and Pull Requests that tend to accumulate during a project\n* Other Tools\n  * Charles Proxy - enabled network traffic sniffing in `debug` builds.\n\n## Architecture\n\nBy dividing a problem into smaller and easier-to-solve sub-problems, we can reduce the complexity of designing and\nmaintaining a large system. Each module is an independent build block serving a clear purpose. We can think about each\nfeature as a reusable component, the equivalent of [microservice](https://en.wikipedia.org/wiki/Microservices) or private\nlibrary.\n\nThe modularized code-base approach provides a few benefits:\n\n- reusability - enable code sharing and building multiple apps from the same foundation. Apps should be a sum of their features where the features are organized as separate modules.\n- [separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns) - each module has a clear API.\n  Feature-related classes live in different modules and can't be referenced without explicit module dependency. We\n  strictly control what is exposed to other parts of your codebase.\n- features can be developed in parallel eg. by different teams\n- each feature can be developed in isolation, independently from other features\n- faster build time\n\n### Module Types And Module Dependencies\n\nThis diagram presents dependencies between project modules (Gradle sub-projects).\n\n![module_dependencies](https://github.com/igorwojda/android-showcase/blob/main/misc/image/module_dependencies.png?raw=true)\n\nWe have three kinds of modules in the application:\n\n- `app` module - this is the main module. It contains code that wires multiple modules together (class, dependency\n  injection setup, `NavHostActivity`, etc.) and fundamental application configuration (retrofit configuration, required\n  permissions setup, custom `Application` class, etc.).\n- `feature_x` modules - the most common type of module containing all code related to a given feature.\n  share some assets or code only between `feature` modules (currently app has no such modules)\n- `feature_base` modules that feature modules depend on to share a common code.\n\n### Feature Module Structure\n\n`Clean Architecture` is implemented at the module level - each module contains its own set of Clean Architecture layers:\n\n![module_dependencies_layers](https://github.com/igorwojda/android-showcase/blob/main/misc/image/module_dependencies_layers.png?raw=true)\n\n\u003e Notice that the `app` module and `library_x` modules structure differs a bit from the feature module structure.\n\nEach feature module contains non-layer components and 3 layers with a distinct set of responsibilities.\n\n![feature_structure](https://github.com/igorwojda/android-showcase/blob/main/misc/image/feature_structure.png?raw=true)\n\n#### Presentation Layer\n\nThis layer is closest to what the user sees on the screen.\n\nThe `presentation` layer mixes `MVVM` and `MVI` patterns:\n\n- `MVVM` - Jetpack `ViewModel` is used to encapsulate a `common UI state`. It exposes the `state` via observable state\n  holder (`Kotlin Flow`)\n- `MVI` - `action` modifies the `common UI state` and emits a new state to a view via `Kotlin Flow`\n\n\u003e The `common state` is a single source of truth for each view. This solution derives from\n\u003e [Unidirectional Data Flow](https://en.wikipedia.org/wiki/Unidirectional_Data_Flow_(computer_science)) and [Redux\n\u003e principles](https://redux.js.org/introduction/three-principles).\n\nThis approach facilitates the creation of consistent states. The state is collected via `collectAsUiStateWithLifecycle`\nmethod. Flows collection happens in a lifecycle-aware manner, so\n[no resources are wasted](https://medium.com/androiddevelopers/consuming-flows-safely-in-jetpack-compose-cde014d0d5a3).\n\nStated is annotated with [Immutable](https://developer.android.com/reference/kotlin/androidx/compose/runtime/Immutable)\nannotation that is used by Jetpack compose to enable composition optimizations.\n\nComponents:\n\n- **View (Fragment)** - observes common view state (through `Kotlin Flow`). Compose transform state (emitted by Kotlin\n  Flow) into application UI Consumes the state and transforms it into application UI (via `Jetpack Compose`). Pass user\n  interactions to `ViewModel`. Views are hard to test, so they should be as simple as possible.\n- **ViewModel** - emits (through `Kotlin Flow`) view state changes to the view and deals with user interactions (these\n  view models are not simply [POJO classes](https://en.wikipedia.org/wiki/Plain_old_Java_object)).\n- **ViewState** - common state for a single view\n- **StateTimeTravelDebugger** - logs actions and view state transitions to facilitate debugging.\n- **NavManager** - singleton that facilitates handling all navigation events inside `NavHostActivity` (instead of\n  separately, inside each view)\n\n#### Domain Layer\n\nThis is the core layer of the application. Notice that the `domain` layer is independent of any other layers. This\nallows making domain models and business logic independent from other layers. In other words, changes in other layers\nwill not affect the `domain` layer eg. changing the database (`data` layer) or screen UI (`presentation` layer) ideally will\nnot result in any code change within the `domain` layer.\n\nComponents:\n\n- **UseCase** - contains business logic\n- **DomainModel** - defines the core structure of the data that will be used within the application. This is the source\n  of truth for application data.\n- **Repository interface** - required to keep the `domain` layer independent from\n  the `data layer` ([Dependency inversion](https://en.wikipedia.org/wiki/Dependency_inversion_principle)).\n\n#### Data Layer\n\nEncapsulates application data. Provides the data to the `domain` layer eg. retrieves data from the internet and cache the\ndata in disk cache (when the device is offline).\n\nComponents:\n\n- **Repository** is exposing data to the `domain` layer. Depending on the application structure and quality of the\n  external API repository can also merge, filter, and transform the data. These operations intend to create\n  a high-quality data source for the `domain` layer. It is the responsibility of the Repository (one or more) to construct\n  Domain models by reading from the `Data Source` and accepting Domain models to be written to the `Data Source`\n- **Mapper** - maps `data model` to `domain model` (to keep `domain` layer independent from the `data` layer).\n\nThis application has two `Data Sources` - `Retrofit` (used for network access) and `Room` (local storage used to access\ndevice persistent memory). These data sources can be treated as an implicit sub-layer. Each data source consists of\nmultiple classes:\n\n- **Retrofit Service** - defines a set of API endpoints\n- **Retrofit Response Model** - definition of the network objects for a given endpoint (top-level model for the data\n  consists of `ApiModels`)\n- **Retrofit Api Data Model** - defines the network objects (sub-objects of the `Response Model`)\n- **Room Database** - persistence database to store app data\n- **Room DAO** - interact with the stored data\n- **Room Entity** - definition of the stored objects\n\nBoth `Retrofit API Data Models` and `Room Entities` contain annotations, so the given framework understands how to parse the\ndata into objects.\n\n### Data Flow\n\nThe below diagram presents application data flow when a user interacts with the `album list screen`:\n\n![app_data_flow](https://github.com/igorwojda/android-showcase/blob/main/misc/image/app_data_flow.png?raw=true)\n\n## Dependency Management\n\nGradle [versions catalog](https://docs.gradle.org/current/userguide/platforms.html#sub:version-catalog) is used as a\ncentralized dependency management third-party dependency coordinates (group, artifact, version) are shared across all\nmodules (Gradle projects and subprojects).\n\nAll of the dependencies are stored in the [settings.gradle.kts](./settings.gradle.kts) file (default location).\nGradle versions catalog consists of a few major sections:\n\n- `[versions]` - declare versions that can be referenced by all dependencies\n- `[libraries]` - declare the aliases to library coordinates\n- `[bundles]` - declare dependency bundles (groups)\n- `[plugins]` - declare Gradle plugin dependencies\n\nEach feature module depends on the `feature_base` module, so dependencies are shared without the need to add them\nexplicitly in each feature module.\n\nThe project enables the `TYPESAFE_PROJECT_ACCESSORS` experimental Gradle feature to generate type-safe accessors to refer other projects.\n\n```kotlin\n// Before\nimplementation(project(\":feature_album\"))\n\n// After\nimplementation(projects.featureAlbum)\n```\n\n## Logcat debugging\n\nTo facilitate debuting project contains logs. You can filter logs to understand app flow. Keywords:\n- `onCreate` see what `Activities` and `Fragments` have been created\n- `Action` - filter all actions performed on the screens to update the UI\n- `Http` - debug network requests and responses\n\n## CI Pipeline\n\nCI is utilizing [GitHub Actions](https://github.com/features/actions). The complete GitHub Actions config is located in\nthe [.github/workflows](.github/workflows) folder.\n\n### Pull Request Verification\n\nSeries of workflows run (in parallel) for every opened PR, and after merging PR to the `main` branch:\n\n* `./gradlew konsist_test:test --rerun-tasks` - checks that source code satisfies Konsist rules\n* `./gradlew lintDebug` - checks that source code satisfies Android lint rules\n* `./gradlew detektCheck` - checks that sourcecode satisfies detekt rules\n* `./gradlew spotlessCheck` - checks that source code satisfies formatting steps.\n* `./gradlew testDebugUnitTest` - run unit tests\n* `./gradlew connectedCheck` - run UI tests\n* `./gradlew :app:bundleDebug` - create an application bundle\n\nThe following tasks cab be executed locally to make codebase compliant with the rules:\n* `./gradlew detektApply` - applies detekt code formatting rules to sourcecode in-place\n* `./gradlew spotlessApply` - applies code formatting steps to the source code in place.\n\n## Design Decisions\n\nRead related articles to have a better understanding of underlying design decisions and various trade-offs.\n\n* [Multiple ways of defining Clean Architecture layers](https://proandroiddev.com/multiple-ways-of-defining-clean-architecture-layers-bbb70afa5d4a)\n* ...\n\n## What This Project Does Not Cover?\n\nThe interface of the app utilizes some of the modern material design components, however, is deliberately kept simple to\nfocus on application architecture and project config.\n\n## Getting Started\n\nThere are a few ways to open this project.\n\n### Android Studio\n\n1. `Android Studio` -\u003e `File` -\u003e `New` -\u003e `From Version control` -\u003e `Git`\n2. Enter `https://github.com/igorwojda/android-showcase.git` into URL field and press `Clone` button\n\n### Command-line And Android Studio\n\n1. Run `git clone https://github.com/igorwojda/android-showcase.git` command to clone the project\n2. Open `Android Studio` and select `File | Open...` from the menu. Select the cloned directory and press `Open` button\n\n### Plugins\n\nIt is recommended to install [Detekt](https://plugins.jetbrains.com/plugin/10761-detekt) to Android Studio. To configure\nthe plugin open Android Studio preferences, open `Tools`, open `Detekt` and add [detekt.yml](detekt.yml) configuration file.\n\n## Upcoming Improvements\n\nThis project is under active development and it is being occasionally refined.\n\nCheck the list of all upcoming\n[enhancements](https://github.com/igorwojda/android-showcase/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aenhancement).\n\n## Inspiration\n\nHere are a few additional resources.\n\n### Cheatsheet\n\n- [Material Theme Builder](https://m3.material.io/theme-builder#/dynamic) - generate dynamic material theme and see it\n  in action\n- [Compose Material 3 Components](https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary)\n  \\- a list containing material components\n- [Core App Quality Checklist](https://developer.android.com/quality) - learn about building the high-quality app\n- [Android Ecosystem Cheat Sheet](https://github.com/igorwojda/android-ecosystem-cheat-sheet) - board containing 200+\n  most important tools\n- [Kotlin Coroutines - Use Cases on Android](https://github.com/LukasLechnerDev/Kotlin-Coroutine-Use-Cases-on-Android) -\n  most popular coroutine usages\n\n### Android Projects\n\nOther high-quality projects will help you to find solutions that work for your project (random order):\n\n- [Compose Samples](https://github.com/android/compose-samples) - repository contains a set of individual Android Studio\n- [Jetpack Compose Playground](https://github.com/Foso/Jetpack-Compose-Playground) - This is a Jetpack Compose example\n  project\n- [Now Android](https://github.com/android/nowinandroid) - fully functional Android app built entirely with Kotlin and\n  Jetpack Compose\n- [WhatsApp Clone Compose](https://github.com/getStream/whatsApp-clone-compose/) - WhatsApp clone app built with Jetpack\n  Compose and Stream Chat SDK for Compose projects to help you learn about Compose in Android\n- [Iosched](https://github.com/google/iosched) - official Android application from google IO 2019 and 2021\n- [Android Architecture Blueprints v2](https://github.com/googlesamples/android-architecture) - a showcase of various\n  Android architecture approaches to developing Android apps\n- [Github Browser Sample](https://github.com/googlesamples/android-architecture-components) - multiple small projects\n  demonstrating usage of Android Architecture Components\n- [Clean Architecture Boilerplate](https://github.com/bufferapp/android-clean-architecture-boilerplate) - clean\n  architecture for Android\n- [Roxie](https://github.com/ww-tech/roxie) - a solid example of a `common state` approach together with very good\n  documentation\n- [Kotlin Android Template](https://github.com/cortinico/kotlin-android-template) - the template that lets you create\n  preconfigured Android Kotlin project in a few seconds\n\n### Other\n\n- [Software Testing Fundamentals](https://softwaretestingfundamentals.com/) - great summary on application testing\n\n## Known Issues\n\n- In Gradle 8.1 the version catalog type safe API is not available for `buildSrc` directory, so dependencies and\n  versions have to be retrieved using type unsafe API:\n  - plugins are retrieved using string plugin ids\n  - versions (`kotlinCompilerExtensionVersion`) are retrieved using string version names\n- No usages are found for the `suspended` Kotlin `invoke`\n  operator ([KTIJ-1053](https://youtrack.jetbrains.com/issue/KTIJ-1053/Find-usages-no-convention-usages-for-suspend-invoke-operator))\n- The `Material You Dynamic Colors` are not correctly applied to Fragment contents (only to Activity)\n- When using `FragmentContainerView`, `NavController` fragment can't be retrieved by\n  using `findNavController()` ([ISSUE-142847973](https://issuetracker.google.com/issues/142847973),\n  [STACKOVERFLOW-59275182](https://stackoverflow.com/questions/59275009/fragmentcontainerview-using-findnavcontroller/59275182))\n- Mockk is unable to mock some methods with implicit `continuation`\n  parameter in the `AlbumListViewModelTest` class ([Issue-957](https://github.com/mockk/mockk/issues/957)), , so test\n  in the `AlbumDetailViewModelTest` was disabled\n- Automatic Kotlin upgrade is disabled in Renovate, because these dependencies have to be updated together with Kotlin:\n  until:\n  - [Jetpack compose compiler](https://developer.android.com/jetpack/androidx/releases/compose-kotlin)\n  - [KSP](https://repo.maven.apache.org/maven2/com/google/devtools/ksp/symbol-processing-gradle-plugin/)\n- [Dynamic feature module](https://developer.android.com/studio/projects/dynamic-delivery) is not supported by\n  `ANDROID_TEST_USES_UNIFIED_TEST_PLATFORM` yet.\n- ktlint `FileName` rule has to be disabled, because it is not compatible with fie contain a single extension\n  [ISSUE-1657](https://github.com/pinterest/ktlint/issues/1657)\n- Delegate import is not provided when a variable has the same name as\n  Delegate ([KTIJ-17403](https://youtrack.jetbrains.com/issue/KTIJ-17403))\n- `androidx.compose.runtime.getValue` and `androidx.compose.runtime.setValue` imports are can't be resolved\n  automatically - they had to be added manually [KTIJ-23200](https://youtrack.jetbrains.com/issue/KTIJ-23200)\n- [ktlint import-ordering](https://github.com/pinterest/ktlint/blob/master/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/ImportOrderingRule.kt)\n  rule conflicts with IDE default formatting rule, so it have to be [.editorconfig](.editorconfig) file.\n  and [KTIJ-16847](https://youtrack.jetbrains.com/issue/KTIJ-16847))\n- False positive \"Unused symbol\" for a custom Android application class referenced in `AndroidManifest.xml`\n  file ([KT-27971](https://youtrack.jetbrains.net/issue/KT-27971))\n- Android lint complains about exceeding access rights to\n  `ArchTaskExecutor` ([Issue 79189568](https://issuetracker.google.com/u/0/issues/79189568))\n- JUnit 5 does not support tests with suspended\n  modifier ([Issue 1914](https://github.com/junit-team/junit5/issues/1914))\n- Custom detekt config is hard to update ([Issue 4517](https://github.com/detekt/detekt/issues/4517))\n- Coil does not provide a way to automatically retry image load, so some images may not be loaded when connection speed\n  is low ([Issue 132](https://github.com/coil-kt/coil/issues/132))\n- `buildFeatures` and `testOptions` blocks are incubating and have to be marked as `@Suppress\n  (\"UnstableApiUsage\")`\n\n## Contribute\n\nThis project is being maintained to stay up to date with leading industry standards. Please check\nthe [CONTRIBUTING](CONTRIBUTING.md) page if you want to help.\n\n## Author\n\n[![Follow me](https://github.com/igorwojda/android-showcase/raw/main/misc/image/avatar.png)](https://twitter.com/igorwojda)\n\n[![Follow me](https://img.shields.io/twitter/follow/igorwojda?style=social)](https://twitter.com/igorwojda)\n\n## License\n\n```\nMIT License\n\nCopyright (c) 2019 Igor Wojda\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and\nassociated documentation files (the \"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial\nportions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT\nLIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\nNO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n```\n\n## Animations License\n\nFlowing animations are distributed under `Creative Commons License 2.0`:\n\n- [Error screen](https://lottiefiles.com/8049-error-screen) by Chetan Potnuru\n- [Building Screen](https://lottiefiles.com/1271-building-screen) by Carolina Cajazeira\n","funding_links":[],"categories":["Kotlin","Samples","Android",":art: Pattern"],"sub_categories":["Containers","MVVM"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figorwojda%2Fandroid-showcase","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Figorwojda%2Fandroid-showcase","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figorwojda%2Fandroid-showcase/lists"}