In social messaging applications, the reliable and robust chat feature is the essential part. In this article, you will learn how to build your own real-time Android WhatsApp project with Jetpack Compose and Stream’s versatile Compose Chat SDK.
Also, you will learn the overall architecture, each layer, and theming that are used in WhatsApp-Clone-Compose project.
Before you dive in, we recommend cloning the WhatsApp-Clone-Compose on your local device with the command below and opening the project with your Android Studio.
If you build WhatsApp Clone Compose on your device, the result will look like this:
WhatsApp Clone Compose follows Google’s app architecture guide, which is the recommended architecture for building a robust, high-quality app. In this post, you’ll learn how the app architecture was designed and how data flows between different layers.
As you see in the figure below, each layer has dedicated components that are very loosely coupled to each other. The arrow means the component has a dependency on the target component along the direction
Each layer has different responsibilities, as defined below:
- Each layer follows unidirectional event/data flow; the UI layer emits user events to the data layer, and the data layer exposes data as a stream to other layers.
- The data layer is designed to work independently from other layers and must be pure, which means it doesn’t have any dependencies on the other layers.
With this loosely coupled architecture, you can increase the reusability of components and scalability of your app.
Now let’s see how each layer works.
WhatsApp Clone Compose is built with 100% Jetpack Compose to draw UI elements, and it configures screens by observing UI states, which come from the ViewModel that holds UI states and restores data when configuration changes.
The ViewModel transforms the business data from the data layer into UI states, and UI elements configure screens following the UI states for success, loading, or error.
UI states represent the business data or exception following the single source-of-truth principle, so you can focus on how to draw UI elements depending on the UI states in the UI layer.
The data layer consists of repositories, which are exposed to other layers as public interfaces. Repositories include business logic that is mostly run on the background thread such as querying data from local databases and fetching remote data from the network.
By exposing the interface of repositories, other layers can observe the business data as a stream such as Kotlin’s Flow.
Repositories have multiple data sources such as the local database and the network. To guarantee the single source-of-truth principle from the multiple resources, repositories are implemented as an offline-first source of business logic as the figure above.
WhatsApp Clone Compose is built with multi-module strategies to improve app development.
- Reusability: Modularizing reusable code properly enable opportunities for code sharing and restrict code access from other modules.
- Parallel Building: Each module can be run in parallel and it reduces the build time.
- Decentralize Team Focusing: Each developer team can assign their dedicated module and they can focus on their own modules.
Modularization allows you to build your feature and write test code independently without any dependencies on other features. As a result, you can achieve loose coupling between modules and high cohesion, which means each module has clearly defined responsibilities for its own domain logic.
WhatsApp Clone Compose has theming components in the
core-designsystem module. The module includes reusable components that are used in UI feature modules, and theme definitions, such as Theme, Background, and Typography.
In this post, you’ll learn how WhatsApp Clone Compose styles the background and theme for overall UI elements.
Styling background is a primary part of application design. To make UI elements have a consistent background color, WhatsApp Clone Compose implemented its own background composable, which is called
BackgroundTheme includes two properties below:
- Color: This property decides the background color of the
- Tonal Elevation: The surface tonal elevation highlights the components depending on the elevation levels. Surfaces at elevation levels +1 to +5 are tinted via color overlays based on the primary color, such as app bars or menus. For more information, check out Material Design 3 Color system.
By wrapping UI elements with
WhatsAppCloneBackground composable like the example below, descendants of the composable content will have the same background color.
Theming is one of the most essential parts of the app design, and you can achieve this easily in Jetpack Compose.
WhatsApp Clone Compose uses Material Theme for styling the overall UI elements, and defining custom color schemes with
Also, WhatsApp Clone Compose defines its own theme,
WhatsAppCloneComposeTheme like the below:
Color themes apply to different color schemes and background colors depending on whether the user device is in dark mode or not.
By wrapping your UI elements with
WhatsAppCloneComposeTheme like the example below, you can see the result of the UI elements being colored according to the defined color scheme.
If you need to apply different colors for specific UI elements, you can just pull out and use the defined color value from the color scheme:
Build the above on your Android Studio, you can see the defined theme applied to the UI elements as shown in the image below:
Now, let’s build a real-time WhatsApp chat feature!
WhatsApp Clone Compose built the chat feature with Stream’s versatile Compose Chat SDK. Stream Chat SDK offers performant chat solutions that have been used by billions of global end-users across thousands of different apps.
Once you have an account, create a project in your Stream Dashboard.
After you create your project, note your API Key.
Lastly, We will disable authentication for convenience, so toggle the Disable Auth Checks button and click the Submit button on your project’s Overview page. Note that this should only be done in development environments.
Before implementing any chat features, import the Stream SDK for Jetpack Compose into your project. Add the below dependencies for your module + app level build.gradle file:
Stream SDK is an open-source project, so you can see all source codes, commit histories, and releases on GitHub.
Note: If you’re completely new to Stream Chat Android, you can also take a look at the Compose Chat Tutorial.
ChatClient is the main entry point for all low-level chat operations, such as connecting and disconnecting users to the Stream server or sending and reacting to messages.
WhatsApp Clone Compose initializes the ChatClient with App Startup and connects a user at once for convenience. Note that we used a development token to connect a user as authentication is disabled.
As we use an initializer, we need to define it inside your AndroidManifest.xml file, and it will be launched when your app started.
Now, let’s build a channel list screen.
Stream SDK provides high-level UI components that allow you to build chat screens without much effort. You can build your channel list screen easily with the
ChannelsScreen composable function:
As you see in the example above, you should wrap the
ChatTheme, which styles chat UI components, such as primary color, typography, and shapes.
Also, navigate your screen or launch activities to display the message list screen with the
onItemClick lambda parameter when users click the channel item.
Build the above on your Android Studio, you will see the result below:
You can build the message list screen easily with the
MessagesScreen composable function like the below:
Next, you should build a
TopAppBar that contains channel information, such as an image and name. To get the channel information, we need to fetch the data from the network using
ChatClient like the below:
You can inject the
ChatClient into your ViewModel with a dependency injection tool like Hilt or you can just get the instance with the
After fetching the channel information via a network call, the
WhatsAppMessagesViewModel transforms the result into UI states that are defined like the below:
WhatsApp Clone Compose models each user interaction as events to handle them in ViewModel.
So you only need to expose
handleEvents method to your UI elements and reduce the API surfaces like the example below:
Finally, you can draw your composable functions depending on the UI states that comes from the ViewModel, such as success, loading, and error:
Note: To load a network image in the
TopAppBar, WhatsApp Clone Compose uses Landscapist, which allows you to fetch and display network images with Glide, Coil, and Fresco.
You will now see the result below:
To learn more about the Compose Chat SDK, try the Compose Chat Tutorial or check out the open-source projects below on GitHub:
You can find the author of this article on Twitter @github_skydoves or GitHub if you have any questions or feedback. If you’d like to stay up to date with Stream, follow us on Twitter @getstream_io for more great technical content.
As always, happy coding!
Originally published at GetStream.io/blog.