Skip to content

GG-3-0-Mobile-Engineering/ME15-Dismaps-GG3MEGP0565-KadekDhivaTiradika

Repository files navigation

DisMaps Android App

Installation

Clone this repository and import into Android Studio

git@github.com:dhivatiradika/ME15-Dismaps-GG3MEGP0565-KadekDhivaTiradika.git

Configuration

API Key:

Add GoogleMaps api key at local.properties with the following info:

MAPS_API_KEY=YOUR_KEY

API URL:

Change API url at NetworkModule at BaseModule.kt files Current API source: https://data.petabencana.id/

private const val url = "ENDPOINT"

Build variants

Use the Android Studio Build Variants button to choose between production and staging flavors combined with debug and release build types

Generating signed APK

From Android Studio:

  1. Build menu
  2. Generate Signed APK...
  3. Fill in the keystore information (you only need to do this once manually and then let Android Studio remember it)

Features

  • Display disaster on map
  • Display disaster as list
  • Filter with date range
  • Filter with province area
  • Filter with selected disaster
  • Water level alert
  • Dark mode

Screenshots

Light Mode

Home screen with disaster live reports Date range filter calendar mode Date range filter edit text input mode Filter applied
Search based on province area Setting Disaster Detail

Dark Mode

Home screen with disaster live reports Date range filter calendar mode Date range filter edit text input mode Filter applied
Search based on province area Setting Disaster Detail

Architecture

Single Activity

Dismaps are build on a single activity, which will host multiple fragments, each with distinct responsibilities.

Main Activity will host four fragment containers, including the header container, main container, bottom sheet container, and bottom sheet header container. These fragment containers are not limited to hosting specific fragments; instead, they are reusable depending on the context and state.

Main Container is the largest among the fragment containers, occupying the full width and height of its parent. Due to its large size, its role is to host components that require large screen space, such as maps, as well as to display important messages like errors or empty states.

Header Container is floating at the top of the screen, its role is to display filter and search bar. In the context of a detailed disaster view, the Header Container also takes on the responsibility of hosting navigation buttons.

Bottom Sheet Container is located inside bottom sheet, granting it draggable behavior and three different states: expanded, half-expanded, and collapsed. This behavior makes the bottom sheet container ideal for hosting scrollable content such as list and detailed information.

Header Bottom Sheet Container will anchored to the top of bottom sheet make it easily noticeable by user, so its responsibility is to host conclusion of information and current states.

Data Sharing Between fragments

These fragments hosted within main activity share common data, which is disaster reports. In addition to the reports, each fragment also maintains states that are utilized to retrieve disaster reports. For example, the list of disasters displayed in the disaster list fragment is generated based on the filter state on search bar fragment. Based on this problem, view model serve as state holder and bridge to domain layer, while view model must be observed and utilized within each fragment, but not attached to fragment lifecycle, so view model need to be crated at fragment but using activity as view model owner so view model scoped to activity lifecycle.

Main activity also need to observe main view model since its role is utilized fragment transaction, decide which fragments are currently displayed. Beside fragment transaction, main activity also had responsibility to manage bottom sheet state. Although each fragment depends on other fragment, this approach make fragment only coupled to view model. For example, disaster list fragment only had one responsibility which is displaying disaster list, its doesn't know if data retrieval is success or not, if filter is applied or not, its only focus on one task, displaying disaster list.

Setting dialog fragment is a dialog that displayed on the top of activity, so its doesn't need fragment container. Setting dialog had different business flow, which is retrieve and utilizing setting data from data store. Since its had different business flow, setting dialog should have separate view model, but in this case fragment as view model owner, so its attached to fragment lifecycle.

Dependency Injection

After project already had well-separated functional set, now its need construction set that will wiring everything together. Dependency injection will act as constructor to serve dependency to all part of the application with various scope. As stated on previous section, different process flow will had different view model, so its need dependency that scoped to view model. Dependency also need to injected to worker for notification alert. Based on this needs, Dismaps used Hilt as dependency injection framework since its cover all this need:

  • @HiltViewModel to inject dependency to view model, so doesn't need to create view model factory.
  • @HiltWorker to inject dependency to worker, so doesn't need to create worker factory.
  • @InstallIn(ViewModelComponent::class) to scope component to view model.
  • @InstallIn(SingletonComponent::class) to scope component to application.