Erply Android Developer test task implementation
- Implementation of a test task for Erply (Android developer) role
- Having a reference/template fully Kotlin/Coroutines gradle-based project using the modern android architecture recommendations
The inspiration comes from Now in Android App.
- Use modern android architecture practices: Guide to app architecture
- Use latest Compose Material 3 components and dynamic color scheme
- Use new Erply PIM API PIM API
- Implement synchronization (full/partial) with remote DB using Erply recommendation and the fact of hourly request limit: Data Syncing
- Use paging data from local DB using Room ORM ( potential large amount of data)
- Use advanced fast search using sqlite fts4 support using Room ORM
- Use well-typed Proto (protobuf) Datastore to store user preferences and session details
- Secure (encrypt) user credentials using device hardware backed keystore (HSM)
- Kotlin DSL for Erply API filtering
.
├── api # Erply API pure (not Android) 'java library' written in Kotlin
├── app # Android application
├── gradle # Gradle wrapper and Version Catalog
...
./app/src/main/kotlin/com/ydanneg/erply
├── data # Data Layer (repositories)
├── database # DB layer (database, entities, daos)
├── datastore # Proto Datastores (user session, user prefereences)
├── di # Dagger Hilt modules
├── domain # Domain Layer (use cases)
├── model # Application models
├── network # Network data sources (Erply API data source)
├── security # Encyption Manager
├── sync # Sync realted logic (worker, sync manager)
└── ui # UI Layer
./app/src/main/kotlin/com/ydanneg/erply/ui
├── app # Main Application composable
├── components # Shared composable components
├── screens # Composable screen components
│ ├── login # Boarding flow: Login related composables and viewmodel
│ └── main # Logged-In flow
│ ├── catalog # List of Product Groups (Catalog) composables and viewmodel
│ ├── products # List of Groups Products composables and viewmodel
│ └── settings # Settings screen and viewmodel
├── theme # Application Compose theme
└── util # Some shared utilities
../app/src/main/kotlin/com/ydanneg/erply/database
├── dao # Dao
├── mappers # Entity<->Domain Model mappers
├── model # Entities
└── util # Utilities, converters
This application follows Official Android Architecture Guide Respected principals:
- Separation of concerns design pattern.
- Single source of truth
- Unidirectional Data Flow Layers:
- UI (MVVM), see Ui Layer
- Data, see Data Layer
- Domain, see Domain Layer
Application consists of the following screens:
- Splash
- Login
- MainScreen (navHost)
- Catalog
- ProductList
- Settings
Catalog shows a list of product groups available for the logged in client.
User can click on a group to see it's products.
User can search products using full-text search.
Groups are sorted by remote order.
Products are sorted by price ASC by default. You can change it.
User can logout and login again.
Synchronized data is preserved for fast sync on next login.
Data is synchronized automatically on app start (logged-in) or triggered manually by pulling lists down.
User credentials are securely persisted so that synchronization can do re-login to acquire new fresh token before synchronization
Synchronization job is automatically scheduled to retry if failed.
- ProductsRepository - Exposes paging products filtered by group and search results from DB
- ProductGroupsRepository - Exposes product groups from DB
- UserDataRepository - Exposes UserData from multiple data stores
- UserSessionRepository - Exposes UserSession from data store, handles login and logout operations
- UserSessionDataSource - Proto DataStore keeping user session persisted
- UserPreferencesDataSource - Proto DataStore keeping user preferences persisted
- ErplyNetworkDataSource - DataSource to Erply API, maps Erply DTOs to app models
- ErplyProductDao - Simple CRUD Product DAO
- ErplyProductGroupDao - Simple CRUD Product Group DAO
- ErplyProductImageDao - Simple CRUD Product Image DAO
- ErplyProductWithImageDao - DAO that combines product and it's image if exists, returns pageable data
- GetServerVersionUseCase - Returns last server timestamp
- GetAllProductsFromRemoteUseCase - Returns products from API, Flow of pages
- GetAllProductImagesFromRemoteUseCase - Returns images from API, flow of pages
- GetAllProductGroupsFromRemoteUseCase - Returns groups from API, flow of pages
- GetAllDeletedProductsFromRemoteUseCase - Returns deleted product ids from API, since provided date
- GetAllDeletedProductImageIdsFromRemoteUseCase - Returns deleted image ids from API, since provided date
- SyncProductsUseCase - Starts products synchronization using provided Synchronizer
- SyncProductImagesUseCase - Starts product images synchronization using provided Synchronizer. Returns boolean result: Success or Failure.
- SyncProductGroupsUseCase - Starts product images synchronization using provided Synchronizer, Returns boolean result: Success or Failure.
- SyncWorker - Implements Synchronizer implementation. Logic of a synchronization. A CoroutineWorker.
- WorkManagerSyncManager - Manages sync status and provides 'requestSync' operation
- MainActivity - Main Activity of the application. ViewModel: MainActivityViewModel
- ErplyApp - Main composable who decides what flow to start: Login or Main. ViewModel: ErplyAppViewModel
- LoginScreen - Login screen composable. ViewModel: LoginScreenViewModel
- MainScreen (NavHost) - Main navigation host. ViewModel: MainScreenViewModel
- CatalogScreen - Composable screen that renders all product groups. ViewModel: CatalogScreenModelView
- ProductsScreen - Composable screen that lists products of a specified group ID. Allows global product search. ViewModel: ProductsScreenViewModel
- SettingsScreen - Settings screen. Allows to switch theme between Dark, Light and System Default
NB! Test are added for demonstration purpose. Code coverage is low.
- ErplyApiFilterTest
- ProductGroupsRepositoryImplTest
- ProductsRepositoryImplTest
- UserDataRepositoryImplTest
- UserSessionRepositoryImplTest
- UserPreferencesDataSourceTest
- UserSessionDataSourceTest
- ErplyAppViewModelTest
- LoginScreenViewModelTest
- ErplyProductDaoTest
- Erply API discovery is not implemented yet. See #2
- Search is only available from inside group view, but anyway working globally. See #1
- Erply PIM API does not provide endpoints to get deleted Product Groups. This limitation now makes fetching all groups every sync. Deleted groups still can be shown in UI.
- Erply Product Categories are not supported.
- Minimum Android version 12
To see all application logs do the following:
adb shell setprop persist.log.tag D
See Issues