Skip to content

Commit

Permalink
Add documentation and update README (#179)
Browse files Browse the repository at this point in the history
  • Loading branch information
AfigAliyev committed Sep 29, 2022
1 parent 9639e81 commit dc8ab6f
Show file tree
Hide file tree
Showing 15 changed files with 425 additions and 16 deletions.
84 changes: 68 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,86 @@
![Cinemax](docs/assets/cinemax.svg)
![Cinemax](docs/images/cinemax-splash.svg)

# Cinemax

Cinemax is a Movies & TV Shows application for Android.

# Preview

<p align="center">
<img src="docs/assets/home.png" width="24%">
<img src="docs/assets/home_2.png" width="24%">
<img src="docs/assets/list.png" width="24%">
<img src="docs/assets/details.png" width="24%">
</p>
<img src="docs/images/screenshot-1-home.png" width="50%"><img src="docs/images/screenshot-2-home.png" width="50%">
<img src="docs/images/screenshot-3-list.png" width="50%"><img src="docs/images/screenshot-4-details.png" width="50%">
<img src="docs/images/screenshot-5-search.png" width="50%"><img src="docs/images/screenshot-6-search.png" width="50%">
<img src="docs/images/screenshot-7-wishlist.png" width="50%"><img src="docs/images/screenshot-8-settings.png" width="50%">

<p align="center">
<img src="docs/assets/search.png" width="24%">
<img src="docs/assets/search_2.png" width="24%">
<img src="docs/assets/wishlist.png" width="24%">
<img src="docs/assets/settings.png" width="24%">
</p>

# Build
# Getting Started

- Generate an API key from [The Movie Database](https://www.themoviedb.org/).
- Put the key in the `local.properties` file.

```
```properties
cinemax.apikey=YOUR_API_KEY_HERE
```

# Development Environment

**Cinemax** uses the Gradle build system and can be imported directly into the latest stable version
of Android Studio (available [here](https://developer.android.com/studio)). The `debug`
build can be built and run using the default configuration.

Once you're up and running, you can refer to the learning journeys below to get a better
understanding of which libraries and tools are being used, the reasoning behind the approaches to
UI, testing, architecture and more, and how all of these different pieces of the project fit
together to create a complete app.

# Build

The app contains the usual `debug` and `release` build variants.

In addition, the `benchmark` variant of `app` is used to test startup performance and generate a
baseline profile (see below for more information).

For normal development use the `debug` variant. For UI performance testing use the `release`
variant.

# Architecture

The **Cinemax** app follows the
[official architecture guidance](https://developer.android.com/topic/architecture)
and is described in detail in the
[architecture learning journey](docs/ArchitectureLearningJourney.md).

![Architecture diagram](docs/images/architecture-1-overall.png)

# Modularization

The **Cinemax** app has been fully modularized and you can find the detailed guidance and
description of the modularization strategy used in
[modularization learning journey](docs/ModularizationLearningJourney.md).

![Modularization graph](docs/images/modularization-graph.png)

# UI

UI components are designed according to the custom design system and built entirely
using [Jetpack Compose](https://developer.android.com/jetpack/compose).

The app has one dark theme that uses predefined colors.

Find out more about the [UI architecture here](docs/ArchitectureLearningJourney.md#ui-layer).

# Baseline profiles

The baseline profile for this app is located
at [`app/src/main/baseline-prof.txt`](app/src/main/baseline-prof.txt). It contains rules that enable
AOT compilation of the critical user path taken during app launch. For more information on baseline
profiles, read [this document](https://developer.android.com/studio/profile/baselineprofiles).

> **Note**: The baseline profile needs to be re-generated for release builds that touch code which changes app startup.
To generate the baseline profile, select the `benchmark` build variant and run the
`BaselineProfileGenerator` benchmark test on an AOSP Android Emulator. Then copy the resulting
baseline profile from the emulator
to [`app/src/main/baseline-prof.txt`](app/src/main/baseline-prof.txt).

# Credits

- Design on [Figma](https://www.figma.com/community/file/1088719884686291024).
Expand Down
132 changes: 132 additions & 0 deletions docs/ArchitectureLearningJourney.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Architecture Learning Journey

In this learning journey you will learn about the Cinemax app architecture: its layers, key classes
and the interactions between them.

## Goals and requirements

The goals for the app architecture are:

- Follow the [official architecture guidance](https://developer.android.com/jetpack/guide) as
closely as possible.
- Easy for developers to understand, nothing too experimental.
- Support multiple developers working on the same codebase.
- Facilitate local and instrumented tests, both on the developer’s machine and using Continuous
Integration (CI).
- Minimize build times.

## Architecture overview

The app architecture has three layers:
a [UI layer](https://developer.android.com/jetpack/guide/ui-layer),
a [data layer](https://developer.android.com/jetpack/guide/data-layer) and
a [domain layer](https://developer.android.com/jetpack/guide/domain-layer).

![Architecture graph](images/architecture-1-overall.png)

The architecture follows a reactive programming model
with [unidirectional data flow](https://developer.android.com/jetpack/guide/ui-layer#udf). With the
data layer at the bottom, the key concepts are:

- Higher layers react to changes in lower layers.
- Events flow down.
- Data flows up.

The data flow is achieved using streams, implemented
using [Kotlin Flows](https://developer.android.com/kotlin/flow).

## Data layer

The data layer is implemented as an offline-first source of app data and business logic. It is the
source of truth for all data in the app.

### Reading data

Data is exposed as data streams. This means each client of the repository must be prepared to react
to data changes.

### Writing data

To write data, the repository provides suspend functions. It is up to the caller to ensure that
their execution is suitably scoped.

### Data sources

A repository may depend on one or more data sources. For example, the `MovieRepositoryImpl`
depends on the following data sources:

<table>
<tr>
<td><strong>Name</strong>
</td>
<td><strong>Backed by</strong>
</td>
<td><strong>Purpose</strong>
</td>
</tr>
<tr>
<td>MovieDatabaseDataSource
</td>
<td><a href="https://developer.android.com/training/data-storage/room">Room/SQLite</a>
</td>
<td>Persistent relational data associated with Movies.
</td>
</tr>
<tr>
<td>MovieNetworkDataSource
</td>
<td>Remote API accessed using Retrofit
</td>
<td>Data for movies, provided through REST API endpoints as JSON.
</td>
</tr>
</table>

## Domain Layer

Each repository has its own models. For example, the `MovieRepository` has a `MovieModel` model and
the `TvShowRepository` has a `TvShowModel` model.

Each repository method has its own use case. For example, the `GetMoviesUseCase` and
the `GetTvShowsUseCase`.

Use cases are the public API for other layers, they provide the _only_ way to access the app data.
The use cases typically offer one or more methods for reading and writing data.

## UI Layer

The [UI layer](https://developer.android.com/topic/architecture/ui-layer) comprises:

- UI elements built using [Jetpack Compose](https://developer.android.com/jetpack/compose)
- [Android ViewModels](https://developer.android.com/topic/libraries/architecture/viewmodel)

The ViewModels receive streams of data from repositories and transform them into UI state. The UI
elements reflect this state, and provide ways for the user to interact with the app. These
interactions are passed as events to the view model where they are processed.

![UI layer architecture diagram](images/architecture-2-ui-layer.png)

### Modeling UI state

UI state is modeled as a sealed hierarchy using interfaces and immutable data classes. State objects
are only ever emitted through the transform of data streams. This approach ensures that:

- the UI state always represents the underlying app data - the app data is the source-of-truth.
- the UI elements handle all possible states.

### Transforming streams into UI state

View models receive streams of data as
cold [flows](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html)
from one or more use cases. These are collected and the view model updates the corresponding UI
state.

### Processing user interactions

User actions are communicated from UI elements to view models using regular method invocations.
These methods are passed to the UI elements as lambda expressions.

## Further reading

- [Guide to app architecture](https://developer.android.com/topic/architecture)
- [Jetpack Compose](https://developer.android.com/jetpack/compose)
Loading

0 comments on commit dc8ab6f

Please sign in to comment.