Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ ConversionApp follows a scalable and testable architecture:
* `feature:commission` applies dynamic commission logic (e.g. first 5 free, 0.7% after).
* `feature:balance` manages the user's wallet-like balance.
* `feature:settings` stores preferences like the dark theme toggle.
* `feature:transaction` stores a history of completed exchanges.
* `core:network`, `core:datastore`, `core:database`, and `core:designsystem` are reusable base modules shared across features.

Each feature module depends only on what it needs and interacts with shared core modules through interfaces.
Expand Down
4 changes: 4 additions & 0 deletions feature/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ Responsible for synchronizing currency rates from the remote API. `SyncUseCase`
## settings

Stores user preferences such as whether dark theme is enabled. It exposes simple use cases via `settingsModule`.

## transaction

Stores completed exchanges so the app can show a transaction history. The module exposes simple use cases to add and retrieve `Transaction` records.
1 change: 1 addition & 0 deletions feature/transaction/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
13 changes: 13 additions & 0 deletions feature/transaction/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Transaction Module

This module records a history of completed currency exchanges.

## Overview
- `Transaction.kt` – data model describing a single exchange.
- `TransactionRepository` – interface for storing and retrieving transactions.
- `TransactionDataRepository` – simple in-memory implementation.
- `AddTransactionUseCase` – saves a transaction to the repository.
- `GetTransactionsUseCase` – returns the stored list of transactions.
- `transactionModule` – Koin definition exposing the repository and use cases.

Use the provided use cases to persist exchanges and display the transaction list in other features.
39 changes: 39 additions & 0 deletions feature/transaction/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
}

android {
namespace = "com.thesetox.transaction"
compileSdk = 35

defaultConfig {
minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}

dependencies {
implementation(libs.koin.android)
implementation(libs.koin.core)

testImplementation(libs.junit)
}
Empty file.
21 changes: 21 additions & 0 deletions feature/transaction/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.thesetox.transaction

/**
* Saves a transaction using [TransactionRepository].
*/
class AddTransactionUseCase(private val repository: TransactionRepository) {
operator fun invoke(transaction: Transaction) {
repository.saveTransaction(transaction)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.thesetox.transaction

/**
* Returns the list of saved transactions.
*/
class GetTransactionsUseCase(private val repository: TransactionRepository) {
operator fun invoke(): List<Transaction> = repository.getTransactions()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.thesetox.transaction

/**
* Represents a single currency exchange transaction.
*
* @property sellCurrency Currency code being sold.
* @property receiveCurrency Currency code being received.
* @property sellAmount Amount sold in [sellCurrency].
* @property receiveAmount Amount received in [receiveCurrency].
* @property commission Fee applied to the transaction.
*/
data class Transaction(
val sellCurrency: String,
val receiveCurrency: String,
val sellAmount: Double,
val receiveAmount: Double,
val commission: Double,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.thesetox.transaction

/**
* Simple in-memory implementation of [TransactionRepository].
*/
class TransactionDataRepository : TransactionRepository {
private val list = mutableListOf<Transaction>()

override fun saveTransaction(transaction: Transaction) {
list.add(transaction)
}

override fun getTransactions(): List<Transaction> = list.toList()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.thesetox.transaction

import org.koin.core.module.dsl.bind
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module

/**
* Koin module providing transaction feature dependencies.
*/
val transactionModule =
module {
singleOf(::TransactionDataRepository) { bind<TransactionRepository>() }
singleOf(::AddTransactionUseCase)
singleOf(::GetTransactionsUseCase)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.thesetox.transaction

/**
* Repository for persisting and retrieving transactions.
*/
interface TransactionRepository {
/** Adds a new [Transaction] to the history. */
fun saveTransaction(transaction: Transaction)

/** Returns all recorded transactions. */
fun getTransactions(): List<Transaction>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.thesetox.transaction

import org.junit.Assert.assertEquals
import org.junit.Test

class AddTransactionUseCaseTest {
@Test
fun `transaction is added to repository`() {
// Arrange
val repository = TransactionDataRepository()
val addTransaction = AddTransactionUseCase(repository)
val getTransactions = GetTransactionsUseCase(repository)
val transaction =
Transaction(
sellCurrency = "EUR",
receiveCurrency = "USD",
sellAmount = 10.0,
receiveAmount = 12.0,
commission = 0.07,
)

// Act
addTransaction(transaction)
val result = getTransactions()

// Assert
assertEquals(listOf(transaction), result)
}
}
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ include(":feature:exchange")
include(":feature:balance")
include(":feature:comission")
include(":feature:settings")
include(":feature:transaction")