Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor currency formatter & handle currencies with zero decimals #65

Merged
merged 2 commits into from
Jan 13, 2024
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
6 changes: 3 additions & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ dependencies {
// Android core components.
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0'
implementation 'androidx.activity:activity-compose:1.8.2'
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.7.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0"
implementation "androidx.navigation:navigation-compose:2.7.6"
// Jetpack compose.
implementation "androidx.compose.ui:ui"
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/com/starry/greenstash/di/MainModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class MainModule {
fun provideWidgetDao(appDatabase: AppDatabase) = appDatabase.getWidgetDao()

@Provides
@Singleton
fun providePreferenceUtil(@ApplicationContext context: Context) = PreferenceUtil(context)

@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class ReminderNotificationSender(
.setContentIntent(createActivityIntent())

val remainingAmount = (goal.targetAmount - goalItem.getCurrentlySavedAmount())
val defCurrency = preferenceUtil.getString(PreferenceUtil.DEFAULT_CURRENCY_STR, "")
val defCurrency = preferenceUtil.getString(PreferenceUtil.DEFAULT_CURRENCY_STR, "")!!

if (goal.deadline.isNotEmpty() && goal.deadline.isNotBlank()) {
val calculatedDays = GoalTextUtils(preferenceUtil).calcRemainingDays(goal)
Expand All @@ -92,8 +92,8 @@ class ReminderNotificationSender(
val amountDay = remainingAmount / calculatedDays.remainingDays
notification.addAction(
R.drawable.ic_notification_deposit,
"${context.getString(R.string.deposit_button)} $defCurrency${
Utils.formatCurrency(Utils.roundDecimal(amountDay))
"${context.getString(R.string.deposit_button)} ${
Utils.formatCurrency(Utils.roundDecimal(amountDay), defCurrency)
}",
createDepositIntent(goal.goalId, amountDay)
)
Expand All @@ -103,8 +103,8 @@ class ReminderNotificationSender(
val amountSemiWeek = remainingAmount / (calculatedDays.remainingDays / 4)
notification.addAction(
R.drawable.ic_notification_deposit,
"${context.getString(R.string.deposit_button)} $defCurrency${
Utils.formatCurrency(Utils.roundDecimal(amountSemiWeek))
"${context.getString(R.string.deposit_button)} ${
Utils.formatCurrency(Utils.roundDecimal(amountSemiWeek), defCurrency)
}",
createDepositIntent(goal.goalId, amountSemiWeek)
)
Expand All @@ -114,8 +114,8 @@ class ReminderNotificationSender(
val amountWeek = remainingAmount / (calculatedDays.remainingDays / 7)
notification.addAction(
R.drawable.ic_notification_deposit,
"${context.getString(R.string.deposit_button)} $defCurrency${
Utils.formatCurrency(Utils.roundDecimal(amountWeek))
"${context.getString(R.string.deposit_button)} ${
Utils.formatCurrency(Utils.roundDecimal(amountWeek), defCurrency)
}",
createDepositIntent(goal.goalId, amountWeek)
)
Expand All @@ -138,11 +138,7 @@ class ReminderNotificationSender(
.setContentTitle(context.getString(R.string.notification_deposited_title))
.setContentText(
context.getString(R.string.notification_deposited_desc)
.format(
"$defCurrency${
Utils.formatCurrency(Utils.roundDecimal(amount))
}"
)
.format(Utils.formatCurrency(Utils.roundDecimal(amount), defCurrency!!))
)
.setStyle(NotificationCompat.BigTextStyle())
.setContentIntent(createActivityIntent())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ import com.starry.greenstash.R

sealed class DrawerScreens(val route: String, val nameResId: Int, val iconResId: Int) {
data object Home : DrawerScreens("home", R.string.drawer_home, R.drawable.ic_nav_home)
data object Backups : DrawerScreens("backups", R.string.drawer_backups, R.drawable.ic_nav_backups)
data object Backups :
DrawerScreens("backups", R.string.drawer_backups, R.drawable.ic_nav_backups)

data object Settings :
DrawerScreens("settings", R.string.drawer_settings, R.drawable.ic_nav_settings)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,10 @@ fun GoalInfoCard(
daysLeftText: String,
progress: Float
) {
val formattedTargetAmount = Utils.formatCurrency(Utils.roundDecimal(targetAmount))
val formattedSavedAmount = Utils.formatCurrency(Utils.roundDecimal(savedAmount))
val formattedTargetAmount =
Utils.formatCurrency(Utils.roundDecimal(targetAmount), currencySymbol)
val formattedSavedAmount =
Utils.formatCurrency(Utils.roundDecimal(savedAmount), currencySymbol)

Card(
modifier = Modifier
Expand Down Expand Up @@ -254,25 +256,21 @@ fun GoalInfoCard(

Spacer(modifier = Modifier.height(8.dp))

Row {
Text(
text = currencySymbol,
fontWeight = FontWeight.Bold,
fontSize = 38.sp,
modifier = Modifier.padding(start = 12.dp)
)
Text(
text = formattedSavedAmount,
fontWeight = FontWeight.Bold,
fontSize = 38.sp,
modifier = Modifier.padding(start = 4.dp)
)
}
Text(
text = formattedSavedAmount,
fontWeight = FontWeight.Bold,
fontSize = 38.sp,
modifier = Modifier.padding(start = 4.dp)
)


Spacer(modifier = Modifier.height(2.dp))

Text(
text = stringResource(id = R.string.info_card_remaining_amount).format("$currencySymbol $formattedTargetAmount"),
text = stringResource(
id = R.string.info_card_remaining_amount,
formattedTargetAmount
),
fontSize = 14.sp,
fontWeight = FontWeight.SemiBold,
modifier = Modifier.padding(start = 12.dp)
Expand Down Expand Up @@ -363,7 +361,7 @@ fun TransactionCard(transactions: List<Transaction>, currencySymbol: String) {
transactions.forEach {
TransactionItem(
transactionType = it.type,
amount = "$currencySymbol${Utils.formatCurrency(Utils.roundDecimal(it.amount))}",
amount = Utils.formatCurrency(Utils.roundDecimal(it.amount), currencySymbol),
date = it.getTransactionDate()
)
}
Expand Down
27 changes: 13 additions & 14 deletions app/src/main/java/com/starry/greenstash/utils/GoalTextUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ class GoalTextUtils(private val preferenceUtil: PreferenceUtil) {
"\n" + context.getString(R.string.currently_saved_complete)
}
text = text.format(
"$defCurrency${Utils.formatCurrency(item.getCurrentlySavedAmount())}",
"$defCurrency${Utils.formatCurrency(item.goal.targetAmount)}"
Utils.formatCurrency(item.getCurrentlySavedAmount(), defCurrency!!),
Utils.formatCurrency(item.goal.targetAmount, defCurrency)
)
return text
}
Expand All @@ -84,29 +84,28 @@ class GoalTextUtils(private val preferenceUtil: PreferenceUtil) {
if ((remainingAmount > 0f)) {
if (item.goal.deadline.isNotEmpty() && item.goal.deadline.isNotBlank()) {
val calculatedDays = calcRemainingDays(item.goal)
val defCurrency = preferenceUtil.getString(PreferenceUtil.DEFAULT_CURRENCY_STR, "")
val defCurrency =
preferenceUtil.getString(PreferenceUtil.DEFAULT_CURRENCY_STR, "")!!
// build description string.
var text = context.getString(R.string.goal_days_left)
.format(calculatedDays.parsedEndDate, calculatedDays.remainingDays) + "\n"
if (calculatedDays.remainingDays > 2) {
text += context.getString(R.string.goal_approx_saving).format(
"$defCurrency${
Utils.formatCurrency(
Utils.roundDecimal(
remainingAmount / calculatedDays.remainingDays
)
)
}"
Utils.formatCurrency(
Utils.roundDecimal(
remainingAmount / calculatedDays.remainingDays
), defCurrency
)
)
text += context.getString(R.string.goal_approx_saving_day)
if (calculatedDays.remainingDays > 14) {
val weeks = calculatedDays.remainingDays / 7
text = text.dropLast(1) // remove full stop
text += ", $defCurrency${
text += ", ${
Utils.formatCurrency(
Utils.roundDecimal(
remainingAmount / weeks
)
), defCurrency
)
}/${
context.getString(
Expand All @@ -116,11 +115,11 @@ class GoalTextUtils(private val preferenceUtil: PreferenceUtil) {
if (calculatedDays.remainingDays > 60) {
val months = calculatedDays.remainingDays / 30
text = text.dropLast(1) // remove full stop
text += ", $defCurrency${
text += ", ${
Utils.formatCurrency(
Utils.roundDecimal(
remainingAmount / months
)
), defCurrency
)
}/${
context.getString(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class PreferenceUtil(context: Context) {
// Preference keys
const val APP_THEME_INT = "theme_settings"
const val MATERIAL_YOU_BOOL = "material_you"
const val DEFAULT_CURRENCY_STR = "default_currency"
const val DEFAULT_CURRENCY_STR = "default_currency_code"
const val DATE_FORMAT_STR = "date_format"
const val APP_LOCK_BOOL = "app_lock"
}
Expand All @@ -48,7 +48,7 @@ class PreferenceUtil(context: Context) {
prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
// Pre-populate some preference data with default values
if (!keyExists(DEFAULT_CURRENCY_STR)) {
putString(DEFAULT_CURRENCY_STR, "$")
putString(DEFAULT_CURRENCY_STR, "USD")
}
if (!keyExists(DATE_FORMAT_STR)) {
putString(DATE_FORMAT_STR, DateStyle.DateMonthYear.pattern)
Expand Down
15 changes: 12 additions & 3 deletions app/src/main/java/com/starry/greenstash/utils/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
import java.math.RoundingMode
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.text.NumberFormat
import java.text.SimpleDateFormat
import java.util.Currency
import java.util.Date
import java.util.Locale

Expand Down Expand Up @@ -64,9 +66,16 @@ object Utils {
}

/** Convert double into currency format */
fun formatCurrency(number: Double): String {
val df = DecimalFormat("#,###.00")
return df.format(number)
fun formatCurrency(amount: Double, currencyCode: String): String {
val nf = NumberFormat.getCurrencyInstance().apply {
currency = Currency.getInstance(currencyCode)
maximumFractionDigits = if (currencyCode in setOf(
"JPY", "DJF", "GNF", "IDR", "KMF", "KRW", "LAK",
"PYG", "RWF", "VND", "VUV", "XAF", "XOF", "XPF"
)
) 0 else 2
}
return nf.format(amount)
}

/**
Expand Down
17 changes: 10 additions & 7 deletions app/src/main/java/com/starry/greenstash/widget/GoalWidget.kt
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,16 @@ class GoalWidget : AppWidgetProvider() {
views.setCharSequence(R.id.widgetTitle, "setText", goalItem.goal.title)

// Set Widget description.
val defCurrency = preferenceUtil.getString(PreferenceUtil.DEFAULT_CURRENCY_STR, "$")
val defCurrency = preferenceUtil.getString(PreferenceUtil.DEFAULT_CURRENCY_STR, "")!!
val widgetDesc = context.getString(R.string.goal_widget_desc)
.format(
"$defCurrency${Utils.formatCurrency(goalItem.getCurrentlySavedAmount())} / $defCurrency${
"${
Utils.formatCurrency(
goalItem.goal.targetAmount
goalItem.getCurrentlySavedAmount(),
defCurrency
)
} / $defCurrency${
Utils.formatCurrency(goalItem.goal.targetAmount, defCurrency)
}"
)
views.setCharSequence(R.id.widgetDesc, "setText", widgetDesc)
Expand All @@ -122,22 +125,22 @@ class GoalWidget : AppWidgetProvider() {
if (goalItem.goal.deadline.isNotEmpty() && goalItem.goal.deadline.isNotBlank()) {
val calculatedDays = goalTextUtils.calcRemainingDays(goalItem.goal)
if (calculatedDays.remainingDays > 2) {
val amountDays = "$defCurrency${
val amountDays = "${
Utils.formatCurrency(
Utils.roundDecimal(
remainingAmount / calculatedDays.remainingDays
)
), defCurrency
)
}/${context.getString(R.string.goal_approx_saving_day)}"
views.setCharSequence(R.id.widgetAmountDay, "setText", amountDays)
views.setViewVisibility(R.id.widgetAmountDay, View.VISIBLE)
}
if (calculatedDays.remainingDays > 7) {
val amountWeeks = "$defCurrency${
val amountWeeks = "${
Utils.formatCurrency(
Utils.roundDecimal(
remainingAmount / (calculatedDays.remainingDays / 7)
)
), defCurrency
)
}/${
context.getString(
Expand Down
Loading