Skip to content
This repository has been archived by the owner on Nov 5, 2024. It is now read-only.

[Feature] Added Decimal Formatting Capability #3568

Merged
merged 4 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ androidx-work = { module = "androidx.work:work-runtime-ktx", version.ref = "andr
androidx-work-testing = { module = "androidx.work:work-testing", version.ref = "androidx-work" }
androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version = "1.3.2" }

# Robolectric
roboelectric = { module = "org.robolectric:robolectric", version = "4.13" }
ILIYANGERMANOV marked this conversation as resolved.
Show resolved Hide resolved

# Material
material = { module = "com.google.android.material:material", version = "1.12.0" }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface Features {
val showTitleSuggestions: BoolFeature
val showCategorySearchBar: BoolFeature
val hideTotalBalance: BoolFeature
val showDecimalNumber: BoolFeature

val allFeatures: List<BoolFeature>
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class IvyFeatures @Inject constructor() : Features {

override val sortCategoriesAlphabetically = BoolFeature(
key = "sort_categories_alphabetically",
group = FeatureGroup.Other,
group = FeatureGroup.Category,
name = "Sort Categories Alphabetically",
description = "Sort income and expenses" +
" categories alphabetically"
Expand Down Expand Up @@ -52,13 +52,25 @@ class IvyFeatures @Inject constructor() : Features {
defaultValue = false
)

override val showDecimalNumber = BoolFeature(
key = "show_decimal_number",
group = FeatureGroup.Other,
name = "Show Decimal Number",
description = "Whether to show the decimal part in amounts",
defaultValue = true
)

override val allFeatures: List<BoolFeature>
get() = listOf(
sortCategoriesAlphabetically,
compactAccountsMode,
compactCategoriesMode,
showTitleSuggestions,
showCategorySearchBar,
hideTotalBalance
hideTotalBalance,
/* will be uncommented when this functionality
* will be available across the application in up-coming PRs
showDecimalNumber
*/
)
}
2 changes: 2 additions & 0 deletions shared/ui/core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ android {
dependencies {
implementation(projects.shared.base)
implementation(projects.shared.domain)

testImplementation(libs.roboelectric)
}
29 changes: 29 additions & 0 deletions shared/ui/core/src/main/java/com/ivy/ui/FormatMoneyUseCase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.ivy.ui

import android.content.Context
import com.ivy.domain.features.Features
import com.ivy.ui.time.DevicePreferences
import dagger.hilt.android.qualifiers.ApplicationContext
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import javax.inject.Inject

class FormatMoneyUseCase @Inject constructor(
private val feature: Features,
ILIYANGERMANOV marked this conversation as resolved.
Show resolved Hide resolved
private val devicePreferences: DevicePreferences,
@ApplicationContext private val context: Context
) {

private val locale = devicePreferences.locale()
private val withoutDecimalFormatter = DecimalFormat("###,###", DecimalFormatSymbols(locale))
private val withDecimalFormatter = DecimalFormat("###,###.00", DecimalFormatSymbols(locale))

suspend fun format(value: Double): String {
val showDecimalPoint = feature.showDecimalNumber.isEnabled(context)

return when (showDecimalPoint) {
true -> withDecimalFormatter.format(value)
false -> withoutDecimalFormatter.format(value)
}
}
}
102 changes: 102 additions & 0 deletions shared/ui/core/src/test/java/com/ivy/ui/FormatMoneyUseCaseTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.ivy.ui

import android.content.Context
import androidx.test.platform.app.InstrumentationRegistry
import com.ivy.domain.features.BoolFeature
import com.ivy.domain.features.FeatureGroup
import com.ivy.domain.features.Features
import com.ivy.ui.time.DevicePreferences
import io.kotest.common.runBlocking
import io.kotest.matchers.shouldBe
import io.mockk.every
import io.mockk.mockk
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.ParameterizedRobolectricTestRunner
import java.util.Locale

@RunWith(ParameterizedRobolectricTestRunner::class)
class FormatMoneyUseCaseTest(private val param: TestData) {

private val context: Context = InstrumentationRegistry.getInstrumentation().context
ILIYANGERMANOV marked this conversation as resolved.
Show resolved Hide resolved
private val features = mockk<Features>()
private val devicePreferences = mockk<DevicePreferences>()

class TestData(
ILIYANGERMANOV marked this conversation as resolved.
Show resolved Hide resolved
val givenInput: Double,
ILIYANGERMANOV marked this conversation as resolved.
Show resolved Hide resolved
val showDecimal: BoolFeature,
ILIYANGERMANOV marked this conversation as resolved.
Show resolved Hide resolved
val locale: Locale,
val expectedOutPut: String
ILIYANGERMANOV marked this conversation as resolved.
Show resolved Hide resolved
)

private lateinit var formatMoneyUseCase: FormatMoneyUseCase

@Test
fun `validate decimal formatting`(): Unit = runBlocking {
// given
every { features.showDecimalNumber } returns param.showDecimal
every { devicePreferences.locale() } returns param.locale
formatMoneyUseCase = FormatMoneyUseCase(features, devicePreferences, context)

// when
val result = formatMoneyUseCase.format(value = param.givenInput)

// then
result shouldBe param.expectedOutPut
}

companion object {
@JvmStatic
@ParameterizedRobolectricTestRunner.Parameters(name = "Input: {0}")
ILIYANGERMANOV marked this conversation as resolved.
Show resolved Hide resolved
fun params() = listOf(
TestData(
givenInput = 1000.12,
showDecimal = BoolFeature(
key = "show_decimal_number",
group = FeatureGroup.Other,
name = "Show Decimal Number",
description = "Whether to show the decimal part in amounts",
defaultValue = true
),
locale = Locale.ENGLISH,
expectedOutPut = "1,000.12"
),
TestData(
givenInput = 1000.12,
showDecimal = BoolFeature(
key = "show_decimal_number",
group = FeatureGroup.Other,
name = "Show Decimal Number",
description = "Whether to show the decimal part in amounts",
defaultValue = false
),
locale = Locale.ENGLISH,
expectedOutPut = "1,000"
),
TestData(
givenInput = 1000.12,
showDecimal = BoolFeature(
key = "show_decimal_number",
group = FeatureGroup.Other,
name = "Show Decimal Number",
description = "Whether to show the decimal part in amounts",
defaultValue = true
),
locale = Locale.GERMAN,
expectedOutPut = "1.000,12"
),
TestData(
givenInput = 1000.12,
showDecimal = BoolFeature(
key = "show_decimal_number",
group = FeatureGroup.Other,
name = "Show Decimal Number",
description = "Whether to show the decimal part in amounts",
defaultValue = false
),
locale = Locale.GERMAN,
expectedOutPut = "1.000"
),
)
}
}