diff --git a/README.md b/README.md index fcca0f5..4140e3d 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/feature/README.md b/feature/README.md index 806cc47..7357b22 100644 --- a/feature/README.md +++ b/feature/README.md @@ -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. diff --git a/feature/transaction/.gitignore b/feature/transaction/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/feature/transaction/.gitignore @@ -0,0 +1 @@ +/build diff --git a/feature/transaction/README.md b/feature/transaction/README.md new file mode 100644 index 0000000..ae61448 --- /dev/null +++ b/feature/transaction/README.md @@ -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. diff --git a/feature/transaction/build.gradle.kts b/feature/transaction/build.gradle.kts new file mode 100644 index 0000000..1a9e096 --- /dev/null +++ b/feature/transaction/build.gradle.kts @@ -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) +} diff --git a/feature/transaction/consumer-rules.pro b/feature/transaction/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/feature/transaction/proguard-rules.pro b/feature/transaction/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/feature/transaction/proguard-rules.pro @@ -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 diff --git a/feature/transaction/src/main/kotlin/com/thesetox/transaction/AddTransactionUseCase.kt b/feature/transaction/src/main/kotlin/com/thesetox/transaction/AddTransactionUseCase.kt new file mode 100644 index 0000000..d500b0f --- /dev/null +++ b/feature/transaction/src/main/kotlin/com/thesetox/transaction/AddTransactionUseCase.kt @@ -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) + } +} diff --git a/feature/transaction/src/main/kotlin/com/thesetox/transaction/GetTransactionsUseCase.kt b/feature/transaction/src/main/kotlin/com/thesetox/transaction/GetTransactionsUseCase.kt new file mode 100644 index 0000000..cac22eb --- /dev/null +++ b/feature/transaction/src/main/kotlin/com/thesetox/transaction/GetTransactionsUseCase.kt @@ -0,0 +1,8 @@ +package com.thesetox.transaction + +/** + * Returns the list of saved transactions. + */ +class GetTransactionsUseCase(private val repository: TransactionRepository) { + operator fun invoke(): List = repository.getTransactions() +} diff --git a/feature/transaction/src/main/kotlin/com/thesetox/transaction/Transaction.kt b/feature/transaction/src/main/kotlin/com/thesetox/transaction/Transaction.kt new file mode 100644 index 0000000..fa8d2a0 --- /dev/null +++ b/feature/transaction/src/main/kotlin/com/thesetox/transaction/Transaction.kt @@ -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, +) diff --git a/feature/transaction/src/main/kotlin/com/thesetox/transaction/TransactionDataRepository.kt b/feature/transaction/src/main/kotlin/com/thesetox/transaction/TransactionDataRepository.kt new file mode 100644 index 0000000..d401217 --- /dev/null +++ b/feature/transaction/src/main/kotlin/com/thesetox/transaction/TransactionDataRepository.kt @@ -0,0 +1,14 @@ +package com.thesetox.transaction + +/** + * Simple in-memory implementation of [TransactionRepository]. + */ +class TransactionDataRepository : TransactionRepository { + private val list = mutableListOf() + + override fun saveTransaction(transaction: Transaction) { + list.add(transaction) + } + + override fun getTransactions(): List = list.toList() +} diff --git a/feature/transaction/src/main/kotlin/com/thesetox/transaction/TransactionModule.kt b/feature/transaction/src/main/kotlin/com/thesetox/transaction/TransactionModule.kt new file mode 100644 index 0000000..07b4a16 --- /dev/null +++ b/feature/transaction/src/main/kotlin/com/thesetox/transaction/TransactionModule.kt @@ -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() } + singleOf(::AddTransactionUseCase) + singleOf(::GetTransactionsUseCase) + } diff --git a/feature/transaction/src/main/kotlin/com/thesetox/transaction/TransactionRepository.kt b/feature/transaction/src/main/kotlin/com/thesetox/transaction/TransactionRepository.kt new file mode 100644 index 0000000..10bf25b --- /dev/null +++ b/feature/transaction/src/main/kotlin/com/thesetox/transaction/TransactionRepository.kt @@ -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 +} diff --git a/feature/transaction/src/test/kotlin/com/thesetox/transaction/AddTransactionUseCaseTest.kt b/feature/transaction/src/test/kotlin/com/thesetox/transaction/AddTransactionUseCaseTest.kt new file mode 100644 index 0000000..9af8207 --- /dev/null +++ b/feature/transaction/src/test/kotlin/com/thesetox/transaction/AddTransactionUseCaseTest.kt @@ -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) + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 196f087..f9cd7b4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -35,3 +35,4 @@ include(":feature:exchange") include(":feature:balance") include(":feature:comission") include(":feature:settings") +include(":feature:transaction")