Skip to content

arrazyfathan/kbbi

Repository files navigation

KBBI

KBBI is an unofficial Android dictionary app for Kamus Besar Bahasa Indonesia. The app combines a remote dictionary API with a bundled local word index so users can search words quickly, inspect meanings in detail, and keep bookmarks and recent search history on-device.

License API

KBBI app preview

Overview

This repository contains the Android client for KBBI. The project is organized as a multi-module Clean Architecture codebase:

  • :app owns application startup, Koin assembly, and the root Navigation3 graph.
  • :core:* contains shared data, domain, logging, presentation, and utility code.
  • :feature:* contains feature-specific presentation, data, and domain modules.
  • Feature navigation is exposed through each feature's navigation package and wired from :app.
  • Presentation uses Jetpack Compose, ViewModels, state, and one-shot UI events.
  • Data access uses repositories, use cases, Room, Ktor, OkHttp, and kotlinx.serialization.
  • Dependency injection uses Koin modules composed at the app boundary.
  • Product flavors are available for development and production.

Features

  • Search Indonesian words from the home screen
  • Browse a bundled local word list from feature/home/data/src/main/assets/entries.json
  • View detailed word entries and meanings
  • Save bookmarked words locally
  • Keep recent search history locally
  • Animated splash screen and Lottie-based loading/empty states
  • Shared design system, UI text handling, error mapping, networking, and logging

Animated preview

Tech Stack

  • Language: Kotlin
  • Build tooling: Gradle, Android Gradle Plugin 9.2.1, Kotlin 2.3.21
  • Java target: Java 17
  • Minimum SDK: 23
  • Target/Compile SDK: 37
  • UI: Jetpack Compose, Material 3, Lottie Compose
  • Navigation: AndroidX Navigation3
  • Architecture: Clean Architecture, MVVM-style presentation, Repository pattern, UseCase layer
  • Async/data: Coroutines, StateFlow, Channel-based events
  • Local storage: Room
  • Networking: Ktor Client, kotlinx.serialization, OkHttp engine/logging
  • Dependency injection: Koin 4.2.1
  • Code quality: Detekt, Ktlint
  • Distribution/automation: Fastlane, GitHub Actions

Module Structure

.
├── app/
│   └── src/main/java/com/arrazyfathan/kbbi/
│       ├── BaseApplication.kt       # Koin startup
│       ├── MainActivity.kt          # Activity entry point
│       ├── di/                      # App-level module assembly
│       └── navigation/              # Root app navigation graph
├── core/
│   ├── data/                        # Shared Ktor client and safe API call helpers
│   ├── di/                          # Shared core Koin modules
│   ├── domain/                      # AppResult, DataError, shared domain primitives
│   ├── logging/                     # App and network logging helpers
│   ├── presentation/
│   │   ├── designsystem/            # Theme, colors, type, icons, resources, components
│   │   └── ui/                      # UiText, DataErrorToText, shared UI helpers
│   └── utils/                       # System bar and platform utilities
├── feature/
│   ├── bookmark/
│   │   └── presentation/            # Bookmark screen, ViewModel, route
│   ├── detail/
│   │   └── presentation/            # Detail screen, ViewModel, route
│   ├── home/
│   │   ├── data/                    # Room, remote/local data sources, repository impl
│   │   ├── domain/                  # Word models, repositories, use cases
│   │   └── presentation/            # Home screen, ViewModel, route
│   ├── splash/
│   │   └── presentation/            # Splash screen and route
│   └── words/
│       └── presentation/            # Word list screen, ViewModel, route
├── fastlane/                        # Release/distribution automation
├── gradle/libs.versions.toml        # Centralized dependency and plugin versions
└── .github/workflows/               # CI and tagged release pipeline

Architecture

The dependency direction is kept inward:

app
 ├── feature:*:presentation
 ├── core:di
 └── core:presentation:designsystem

feature:*:presentation
 ├── feature:home:domain
 ├── core:domain
 ├── core:presentation:ui
 └── core:presentation:designsystem

feature:home:data
 ├── feature:home:domain
 ├── core:data
 ├── core:domain
 └── core:logging

core modules
 └── shared primitives with no feature ownership

HttpClientFactory and SafeApiCall live in :core:data so every feature data module can reuse the same network setup. UiText and DataErrorToText live in :core:presentation:ui so presentation modules can map domain/data errors to localized UI messages consistently.

Application Flow

The app starts at the splash destination, then enters the main flow owned by the root navigation graph in :app.

  • Home: Search words, display loading/error states, and store recent searches.
  • Words: Filter the bundled local word index, then fetch word details.
  • Bookmarks: View and remove locally saved entries.
  • Detail: Show meanings for a selected word and toggle bookmark state.

Each feature exposes its route from a navigation package, while AppNavigation in :app composes those destinations into the app graph.

Data Sources

Remote API

Local Data

  • Room database: stores history and bookmark data in kbbi_db
  • Asset file: feature/home/data/src/main/assets/entries.json provides the local searchable word list

Requirements

To build the project locally, use:

  • Android Studio with current Android SDK tooling
  • JDK 17
  • Android SDK Platform 37
  • An Android device or emulator for runtime testing

Getting Started

1. Clone the repository

git clone https://github.com/arrazyfathan/kbbi.git
cd kbbi

2. Configure the Android SDK

Your local.properties should point to a valid Android SDK installation:

sdk.dir=/path/to/Android/sdk

3. Sync dependencies

./gradlew help

If Gradle sync succeeds, the project is ready to open in Android Studio.

Build Variants

The app defines one flavor dimension, stage, with two product flavors:

  • development uses application ID com.arrazyfathan.kbbi.dev
  • production uses application ID com.arrazyfathan.kbbi

Examples:

./gradlew assembleDevelopmentDebug
./gradlew assembleProductionDebug

Release APK names are customized automatically:

  • Production: kbbi-v<version>-release.apk
  • Non-production: kbbi-<flavor>-v<version>-release.apk

Version values are driven by app/version.properties.

Running the App

For local development, the normal entry point is the development debug build:

./gradlew installDevelopmentDebug

Or from Android Studio, choose the developmentDebug variant and run the app configuration.

Testing

Local unit tests are split across the app, core, and feature modules. Instrumented tests currently live under the feature data layer where Android-dependent Room behavior is validated.

Run JVM unit tests:

./gradlew testDevelopmentDebugUnitTest :core:logging:testDebugUnitTest :core:domain:test :feature:home:data:testDebugUnitTest :feature:home:domain:test

Compile Android tests:

./gradlew :feature:home:data:compileDebugAndroidTestKotlin

Run Android tests on a connected device or emulator:

./gradlew :feature:home:data:connectedDebugAndroidTest

Coverage

The project uses the JetBrains Kover plugin. For the development debug variant:

./gradlew app:koverLogDevelopmentDebug
./gradlew app:koverHtmlReportDevelopmentDebug

The HTML report is generated at app/build/reports/kover/htmlDevelopmentDebug/index.html.

Quality and Validation

Useful validation commands:

./gradlew lintDevelopmentDebug
./gradlew detekt
./gradlew ktlintCheck
./gradlew assembleDevelopmentDebug

A focused post-refactor validation pass:

./gradlew testDevelopmentDebugUnitTest :core:logging:testDebugUnitTest :core:domain:test :feature:home:data:testDebugUnitTest :feature:home:domain:test :feature:home:data:compileDebugAndroidTestKotlin

Release Signing

Release builds are intentionally blocked unless signing is configured. The Gradle build expects these values through either Gradle properties or environment variables:

ANDROID_KEYSTORE_PATH
ANDROID_KEYSTORE_PASSWORD
ANDROID_KEY_ALIAS
ANDROID_KEY_PASSWORD

Example:

export ANDROID_KEYSTORE_PATH=/absolute/path/to/release.keystore
export ANDROID_KEYSTORE_PASSWORD=your-store-password
export ANDROID_KEY_ALIAS=your-key-alias
export ANDROID_KEY_PASSWORD=your-key-password
./gradlew assembleProductionRelease

Without those values, any signed release packaging task will fail by design.

Fastlane

The repository includes Fastlane setup.

Install Ruby dependencies:

bundle install

Available lane:

bundle exec fastlane android test

Current behavior:

  • android test runs Gradle tests

CI/CD

GitHub Actions workflow: .github/workflows/android.yml

Pull requests and pushes to main

The validate job runs:

./gradlew testDevelopmentDebugUnitTest lintDevelopmentDebug assembleDevelopmentDebug --stacktrace

If successful, it uploads the development debug APK as a workflow artifact.

Tagged releases

When a git tag is pushed, the release job:

  1. Validates signing secrets
  2. Builds assembleProductionRelease
  3. Uploads the signed production APK as an artifact
  4. Publishes a GitHub release with generated release notes

Required GitHub secrets:

  • ANDROID_KEYSTORE_BASE64
  • ANDROID_KEYSTORE_PASSWORD
  • ANDROID_KEY_ALIAS
  • ANDROID_KEY_PASSWORD

Design and UX Notes

The current app includes:

  • Compose-first screen implementation
  • Material 3 components and app theming
  • Shared design system module for theme, type, colors, icons, resources, and components
  • Shared UiText and DataErrorToText for localized presentation messages
  • Custom splash screen animation
  • Lottie-based loading and empty states
  • AndroidX edge-to-edge system bar setup
  • Compose previews for key screens and content components

Screenshots and Metrics

MAD Score

summary kotlin jetpack

Download

Latest published APK:

License

Designed and developed by 2022 arrazyfathan (Ar Razy Fathan Rabbani)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.