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

Commit 9d56c95

Browse files
committed
Updated FormatMoneyUseCase
1 parent 0e112f2 commit 9d56c95

File tree

24 files changed

+126
-29
lines changed

24 files changed

+126
-29
lines changed

screen/edit-transaction/src/main/java/com/ivy/transaction/EditTransactionScreen.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ import com.ivy.navigation.navigation
5656
import com.ivy.navigation.screenScopedViewModel
5757
import com.ivy.ui.R
5858
import com.ivy.wallet.domain.data.CustomExchangeRateState
59-
import com.ivy.wallet.domain.data.IvyCurrency
59+
import com.ivy.legacy.domain.data.IvyCurrency
6060
import com.ivy.wallet.domain.deprecated.logic.model.CreateAccountData
6161
import com.ivy.wallet.domain.deprecated.logic.model.CreateCategoryData
6262
import com.ivy.wallet.ui.edit.core.Category

screen/home/src/main/java/com/ivy/home/HomeTab.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ import com.ivy.navigation.IvyPreview
5353
import com.ivy.navigation.screenScopedViewModel
5454
import com.ivy.ui.R
5555
import com.ivy.ui.rememberScrollPositionListState
56-
import com.ivy.wallet.domain.data.IvyCurrency
56+
import com.ivy.legacy.domain.data.IvyCurrency
5757
import com.ivy.wallet.domain.pure.data.IncomeExpensePair
5858
import com.ivy.wallet.ui.theme.modal.BufferModal
5959
import com.ivy.wallet.ui.theme.modal.BufferModalData

screen/import-data/src/main/java/com/ivy/importdata/csv/domain/CSVImporterV2.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import com.ivy.legacy.datamodel.Account
2727
import com.ivy.legacy.datamodel.temp.toLegacyDomain
2828
import com.ivy.legacy.datamodel.toEntity
2929
import com.ivy.legacy.utils.toLowerCaseLocal
30-
import com.ivy.wallet.domain.data.IvyCurrency
30+
import com.ivy.legacy.domain.data.IvyCurrency
3131
import com.ivy.wallet.domain.pure.util.nextOrderNum
3232
import com.ivy.wallet.ui.theme.Green
3333
import com.ivy.wallet.ui.theme.IvyDark

screen/loans/src/main/java/com/ivy/loans/loandetails/LoanDetailsScreen.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ import com.ivy.navigation.TransactionsScreen
6565
import com.ivy.navigation.navigation
6666
import com.ivy.ui.R
6767
import com.ivy.ui.time.TimeFormatter
68-
import com.ivy.wallet.domain.data.IvyCurrency
68+
import com.ivy.legacy.domain.data.IvyCurrency
6969
import com.ivy.wallet.ui.theme.Gradient
7070
import com.ivy.wallet.ui.theme.Gray
7171
import com.ivy.wallet.ui.theme.MediumBlack

screen/onboarding/src/main/java/com/ivy/onboarding/OnboardingDetailState.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package com.ivy.onboarding
33
import androidx.compose.runtime.Immutable
44
import com.ivy.data.model.Category
55
import com.ivy.legacy.data.model.AccountBalance
6-
import com.ivy.wallet.domain.data.IvyCurrency
6+
import com.ivy.legacy.domain.data.IvyCurrency
77
import com.ivy.wallet.domain.deprecated.logic.model.CreateAccountData
88
import com.ivy.wallet.domain.deprecated.logic.model.CreateCategoryData
99
import kotlinx.collections.immutable.ImmutableList

screen/onboarding/src/main/java/com/ivy/onboarding/OnboardingEvent.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package com.ivy.onboarding
22

33
import com.ivy.data.model.Category
44
import com.ivy.legacy.datamodel.Account
5-
import com.ivy.wallet.domain.data.IvyCurrency
5+
import com.ivy.legacy.domain.data.IvyCurrency
66
import com.ivy.wallet.domain.deprecated.logic.model.CreateAccountData
77
import com.ivy.wallet.domain.deprecated.logic.model.CreateCategoryData
88

screen/onboarding/src/main/java/com/ivy/onboarding/OnboardingScreen.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import com.ivy.onboarding.steps.OnboardingSetCurrency
1616
import com.ivy.onboarding.steps.OnboardingSplashLogin
1717
import com.ivy.onboarding.steps.OnboardingType
1818
import com.ivy.onboarding.viewmodel.OnboardingViewModel
19-
import com.ivy.wallet.domain.data.IvyCurrency
19+
import com.ivy.legacy.domain.data.IvyCurrency
2020
import com.ivy.wallet.domain.deprecated.logic.model.CreateAccountData
2121
import com.ivy.wallet.domain.deprecated.logic.model.CreateCategoryData
2222
import kotlinx.collections.immutable.ImmutableList

screen/onboarding/src/main/java/com/ivy/onboarding/steps/OnboardingSetCurrency.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import com.ivy.legacy.IvyWalletPreview
2727
import com.ivy.legacy.utils.setStatusBarDarkTextCompat
2828
import com.ivy.navigation.navigation
2929
import com.ivy.ui.R
30-
import com.ivy.wallet.domain.data.IvyCurrency
30+
import com.ivy.legacy.domain.data.IvyCurrency
3131
import com.ivy.wallet.ui.theme.GradientIvy
3232
import com.ivy.wallet.ui.theme.White
3333
import com.ivy.wallet.ui.theme.components.BackButton

screen/onboarding/src/main/java/com/ivy/onboarding/viewmodel/OnboardingRouter.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import com.ivy.navigation.MainScreen
1616
import com.ivy.navigation.Navigation
1717
import com.ivy.navigation.OnboardingScreen
1818
import com.ivy.onboarding.OnboardingState
19-
import com.ivy.wallet.domain.data.IvyCurrency
19+
import com.ivy.legacy.domain.data.IvyCurrency
2020
import com.ivy.wallet.domain.deprecated.logic.PreloadDataLogic
2121
import com.ivy.wallet.domain.deprecated.logic.model.CreateAccountData
2222
import com.ivy.wallet.domain.deprecated.logic.model.CreateCategoryData

screen/onboarding/src/main/java/com/ivy/onboarding/viewmodel/OnboardingViewModel.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import com.ivy.onboarding.OnboardingDetailState
2727
import com.ivy.onboarding.OnboardingEvent
2828
import com.ivy.onboarding.OnboardingState
2929
import com.ivy.wallet.domain.action.account.AccountsAct
30-
import com.ivy.wallet.domain.data.IvyCurrency
30+
import com.ivy.legacy.domain.data.IvyCurrency
3131
import com.ivy.wallet.domain.deprecated.logic.CategoryCreator
3232
import com.ivy.wallet.domain.deprecated.logic.PreloadDataLogic
3333
import com.ivy.wallet.domain.deprecated.logic.WalletAccountLogic

screen/settings/src/main/java/com/ivy/settings/SettingsScreen.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ import com.ivy.navigation.ReleasesScreen
5757
import com.ivy.navigation.navigation
5858
import com.ivy.navigation.screenScopedViewModel
5959
import com.ivy.ui.R
60-
import com.ivy.wallet.domain.data.IvyCurrency
60+
import com.ivy.legacy.domain.data.IvyCurrency
6161
import com.ivy.wallet.ui.theme.Blue
6262
import com.ivy.wallet.ui.theme.Gradient
6363
import com.ivy.wallet.ui.theme.GradientGreen

shared/ui/core/src/main/java/com/ivy/ui/FormatMoneyUseCase.kt

+59-6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ const val THOUSAND = 1_000
1313
const val MILLION = 1_000_000
1414
const val BILLION = 1_000_000_000
1515

16+
/**
17+
* A use case class responsible for formatting currency and cryptocurrency values based on user preferences.
18+
* It supports regular currency formatting with or without decimal places, as well as shortened formats
19+
* (e.g., "1k", "1m"). For cryptocurrency, it formats up to 9 decimal places and removes unnecessary trailing zeros.
20+
*
21+
* @property features Provides feature toggles to customize app behavior.
22+
* @property devicePreferences Manages user-specific preferences for locale and other device settings.
23+
* @property context Application context, used for feature check and resource access.
24+
*/
1625
class FormatMoneyUseCase @Inject constructor(
1726
private val features: Features,
1827
private val devicePreferences: DevicePreferences,
@@ -23,25 +32,69 @@ class FormatMoneyUseCase @Inject constructor(
2332
private val withoutDecimalFormatter = DecimalFormat("###,###", DecimalFormatSymbols(locale))
2433
private val withDecimalFormatter = DecimalFormat("###,###.00", DecimalFormatSymbols(locale))
2534
private val shortenAmountFormatter = DecimalFormat("###,###.##", DecimalFormatSymbols(locale))
35+
private val cryptoFormatter =
36+
DecimalFormat("###,###,##0.${"0".repeat(9)}", DecimalFormatSymbols(locale))
2637

27-
suspend fun format(value: Double, shortenAmount: Boolean): String {
28-
if (abs(value) >= THOUSAND && shortenAmount) {
29-
val result = if (abs(value) >= BILLION) {
38+
/**
39+
* Formats a currency or cryptocurrency amount based on the input parameters.
40+
*
41+
* @param value The numeric value to format.
42+
* @param shortenAmount Flag to indicate if the amount should be shortened (e.g., "1k" for 1,000).
43+
* @param isCrypto Flag to indicate if the value is a cryptocurrency, enabling up to 9 decimal places.
44+
* @return The formatted string representation of the value.
45+
*/
46+
suspend fun format(value: Double, shortenAmount: Boolean, isCrypto: Boolean = false): String {
47+
val result = if (isCrypto) {
48+
formatCrypto(value)
49+
} else if (abs(value) >= THOUSAND && shortenAmount) {
50+
if (abs(value) >= BILLION) {
3051
"${shortenAmountFormatter.format(value / BILLION)}b"
3152
} else if (abs(value) >= MILLION) {
3253
"${shortenAmountFormatter.format(value / MILLION)}m"
3354
} else {
3455
"${shortenAmountFormatter.format(value / THOUSAND)}k"
3556
}
36-
return result
3757
} else {
3858
val showDecimalPoint = features.showDecimalNumber.isEnabled(context)
3959

4060
val formatter = when (showDecimalPoint) {
4161
true -> withDecimalFormatter
4262
false -> withoutDecimalFormatter
4363
}
44-
return formatter.format(value)
64+
formatter.format(value)
4565
}
66+
67+
return result
68+
}
69+
70+
/**
71+
* Formats a cryptocurrency value with up to 9 decimal places, removing unnecessary trailing zeros.
72+
*
73+
* @param value The cryptocurrency value to format.
74+
* @return The formatted cryptocurrency value as a string.
75+
*/
76+
private fun formatCrypto(value: Double): String {
77+
val result = cryptoFormatter.format(value)
78+
return when {
79+
result.lastOrNull() == localDecimalSeparator().firstOrNull() -> {
80+
val newResult = result.dropLast(1)
81+
newResult.ifEmpty { "0" }
82+
}
83+
84+
result.isEmpty() -> {
85+
"0"
86+
}
87+
88+
else -> result
89+
}
90+
}
91+
92+
/**
93+
* Retrieves the local decimal separator based on the user's locale.
94+
*
95+
* @return The decimal separator as a string.
96+
*/
97+
private fun localDecimalSeparator(): String {
98+
return DecimalFormatSymbols(locale).decimalSeparator.toString()
4699
}
47-
}
100+
}

shared/ui/core/src/test/java/com/ivy/ui/FormatMoneyUseCaseTest.kt

+45-1
Original file line numberDiff line numberDiff line change
@@ -24,79 +24,122 @@ class FormatMoneyUseCaseTest {
2424
val amount: Double,
2525
val showDecimal: Boolean,
2626
val shortenAmount: Boolean,
27+
val isCrypto: Boolean,
2728
val locale: Locale,
2829
val expectedOutput: String
2930
) {
3031
ENG_SHOW_DECIMAL(
3132
amount = 1_000.12,
3233
showDecimal = true,
3334
shortenAmount = false,
35+
isCrypto = false,
3436
locale = Locale.ENGLISH,
3537
expectedOutput = "1,000.12"
3638
),
3739
ENG_HIDE_DECIMAL(
3840
amount = 1_000.12,
3941
showDecimal = false,
4042
shortenAmount = false,
43+
isCrypto = false,
4144
locale = Locale.ENGLISH,
4245
expectedOutput = "1,000"
4346
),
4447
GERMAN_SHOW_DECIMAL(
4548
amount = 1_000.12,
4649
showDecimal = true,
4750
shortenAmount = false,
51+
isCrypto = false,
4852
locale = Locale.GERMAN,
4953
expectedOutput = "1.000,12"
5054
),
5155
GERMAN_HIDE_DECIMAL(
5256
amount = 1_000.12,
5357
showDecimal = false,
5458
shortenAmount = false,
59+
isCrypto = false,
5560
locale = Locale.GERMAN,
5661
expectedOutput = "1.000"
5762
),
5863
ENGLISH_1K_SHORT_AMT(
5964
amount = 13_000.10,
6065
showDecimal = true,
6166
shortenAmount = true,
67+
isCrypto = false,
6268
locale = Locale.ENGLISH,
6369
expectedOutput = "13k"
6470
),
6571
ENGLISH_MILLION_SHORT_AMT(
6672
amount = 1_233_500.10,
6773
showDecimal = true,
6874
shortenAmount = true,
75+
isCrypto = false,
6976
locale = Locale.ENGLISH,
7077
expectedOutput = "1.23m"
7178
),
7279
ENGLISH_BILLION_SHORT_AMT(
7380
amount = 1_233_000_000.10,
7481
showDecimal = true,
7582
shortenAmount = true,
83+
isCrypto = false,
7684
locale = Locale.ENGLISH,
7785
expectedOutput = "1.23b"
7886
),
7987
GERMAN_1K_SHORT_AMT(
8088
amount = 13_000.10,
8189
showDecimal = true,
8290
shortenAmount = true,
91+
isCrypto = false,
8392
locale = Locale.GERMAN,
8493
expectedOutput = "13k"
8594
),
8695
GERMAN_MILLION_SHORT_AMT(
8796
amount = 1_233_500.10,
8897
showDecimal = true,
8998
shortenAmount = true,
99+
isCrypto = false,
90100
locale = Locale.GERMAN,
91101
expectedOutput = "1,23m"
92102
),
93103
GERMAN_BILLION_SHORT_AMT(
94104
amount = 1_233_000_000.10,
95105
showDecimal = true,
96106
shortenAmount = true,
107+
isCrypto = false,
97108
locale = Locale.GERMAN,
98109
expectedOutput = "1,23b"
99110
),
111+
ENG_SHOW_DECIMAL_CRYPTO(
112+
amount = 123_456.0,
113+
showDecimal = true,
114+
shortenAmount = false,
115+
isCrypto = true,
116+
locale = Locale.ENGLISH,
117+
expectedOutput = "123,456.000000000"
118+
),
119+
ENG_HIDE_DECIMAL_CRYPTO(
120+
amount = 123_456.0,
121+
showDecimal = false,
122+
shortenAmount = false,
123+
isCrypto = true,
124+
locale = Locale.ENGLISH,
125+
expectedOutput = "123,456.000000000"
126+
),
127+
GERMAN_SHOW_DECIMAL_CRYPTO(
128+
amount = 123_456.0,
129+
showDecimal = true,
130+
shortenAmount = false,
131+
isCrypto = true,
132+
locale = Locale.GERMAN,
133+
expectedOutput = "123.456,000000000"
134+
),
135+
GERMAN_HIDE_DECIMAL_CRYPTO(
136+
amount = 123_456.0,
137+
showDecimal = false,
138+
shortenAmount = false,
139+
isCrypto = true,
140+
locale = Locale.GERMAN,
141+
expectedOutput = "123.456,000000000"
142+
),
100143
}
101144

102145
private lateinit var formatMoneyUseCase: FormatMoneyUseCase
@@ -114,7 +157,8 @@ class FormatMoneyUseCaseTest {
114157
// when
115158
val result = formatMoneyUseCase.format(
116159
value = testCase.amount,
117-
shortenAmount = testCase.shortenAmount
160+
shortenAmount = testCase.shortenAmount,
161+
isCrypto = testCase.isCrypto
118162
)
119163

120164
// then

temp/legacy-code/src/main/java/com/ivy/legacy/domain/data/IvyCurrency.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.ivy.wallet.domain.data
1+
package com.ivy.legacy.domain.data
22

33
import android.icu.util.Currency
44
import androidx.compose.runtime.Immutable

temp/legacy-code/src/main/java/com/ivy/legacy/domain/deprecated/logic/csv/CSVImporter.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import com.ivy.legacy.datamodel.toEntity
2727
import com.ivy.legacy.utils.convertLocalToUTC
2828
import com.ivy.legacy.utils.timeNowUTC
2929
import com.ivy.legacy.utils.toLowerCaseLocal
30-
import com.ivy.wallet.domain.data.IvyCurrency
30+
import com.ivy.legacy.domain.data.IvyCurrency
3131
import com.ivy.wallet.domain.deprecated.logic.csv.model.RowMapping
3232
import com.ivy.wallet.domain.pure.util.nextOrderNum
3333
import com.opencsv.CSVReaderBuilder

temp/legacy-code/src/main/java/com/ivy/legacy/legacy/ui/theme/components/CurrencyPicker.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ import com.ivy.legacy.utils.keyboardOnlyWindowInsets
5353
import com.ivy.legacy.utils.onScreenStart
5454
import com.ivy.legacy.utils.toLowerCaseLocal
5555
import com.ivy.ui.R
56-
import com.ivy.wallet.domain.data.IvyCurrency
56+
import com.ivy.legacy.domain.data.IvyCurrency
5757
import com.ivy.wallet.ui.theme.GradientGreen
5858
import com.ivy.wallet.ui.theme.GradientIvy
5959
import com.ivy.wallet.ui.theme.Ivy

temp/legacy-code/src/main/java/com/ivy/legacy/legacy/ui/theme/components/CustomExchangeRateCard.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import com.ivy.design.l0_system.style
2424
import com.ivy.legacy.IvyWalletComponentPreview
2525
import com.ivy.legacy.utils.format
2626
import com.ivy.ui.R
27-
import com.ivy.wallet.domain.data.IvyCurrency
27+
import com.ivy.legacy.domain.data.IvyCurrency
2828
import com.ivy.wallet.ui.theme.Orange
2929

3030
@Deprecated("Old design system. Use `:ivy-design` and Material3")

temp/legacy-code/src/main/java/com/ivy/legacy/legacy/ui/theme/modal/CurrencyModal.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import com.ivy.design.l0_system.UI
2222
import com.ivy.design.l0_system.style
2323
import com.ivy.legacy.IvyWalletPreview
2424
import com.ivy.ui.R
25-
import com.ivy.wallet.domain.data.IvyCurrency
25+
import com.ivy.legacy.domain.data.IvyCurrency
2626
import com.ivy.wallet.ui.theme.Gray
2727
import com.ivy.wallet.ui.theme.components.CurrencyPicker
2828
import java.util.UUID

temp/legacy-code/src/main/java/com/ivy/legacy/legacy/ui/theme/modal/LoanModal.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import com.ivy.legacy.utils.selectEndTextFieldValue
5252
import com.ivy.design.utils.thenIf
5353
import com.ivy.legacy.legacy.ui.theme.modal.ModalNameInput
5454
import com.ivy.ui.R
55-
import com.ivy.wallet.domain.data.IvyCurrency
55+
import com.ivy.legacy.domain.data.IvyCurrency
5656
import com.ivy.wallet.domain.deprecated.logic.model.CreateAccountData
5757
import com.ivy.wallet.domain.deprecated.logic.model.CreateLoanData
5858
import com.ivy.wallet.ui.theme.GradientIvy

temp/legacy-code/src/main/java/com/ivy/legacy/legacy/ui/theme/modal/edit/AccountModal.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import com.ivy.legacy.utils.selectEndTextFieldValue
3737
import com.ivy.legacy.utils.toLowerCaseLocal
3838
import com.ivy.legacy.utils.toUpperCaseLocal
3939
import com.ivy.ui.R
40-
import com.ivy.wallet.domain.data.IvyCurrency
40+
import com.ivy.legacy.domain.data.IvyCurrency
4141
import com.ivy.wallet.domain.deprecated.logic.model.CreateAccountData
4242
import com.ivy.wallet.ui.theme.Gray
4343
import com.ivy.wallet.ui.theme.Ivy

temp/legacy-code/src/main/java/com/ivy/legacy/ui/component/IncomeExpenseCards.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import com.ivy.design.l0_system.style
2828
import com.ivy.legacy.utils.drawColoredShadow
2929
import com.ivy.legacy.utils.format
3030
import com.ivy.ui.R
31-
import com.ivy.wallet.domain.data.IvyCurrency
31+
import com.ivy.legacy.domain.data.IvyCurrency
3232
import com.ivy.wallet.ui.theme.Gradient
3333
import com.ivy.wallet.ui.theme.Green
3434
import com.ivy.wallet.ui.theme.MediumBlack

0 commit comments

Comments
 (0)