/* * Copyright (C) 2012-2016 The Android Money Manager Ex Project Team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.money.manager.ex.core; import android.content.Context; import android.text.TextUtils; import android.widget.TextView; import com.money.manager.ex.Constants; import com.money.manager.ex.MoneyManagerApplication; import com.money.manager.ex.R; import com.money.manager.ex.currency.CurrencyService; import com.money.manager.ex.domainmodel.Currency; import com.money.manager.ex.log.ExceptionHandler; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.util.Locale; import javax.inject.Inject; import info.javaperformance.money.Money; import timber.log.Timber; /** * Utilities to assist with formatting dates and numbers. */ public class FormatUtilities { public FormatUtilities(Context context) { this.context = context; MoneyManagerApplication.getApp().iocComponent.inject(this); } @Inject public FormatUtilities(MoneyManagerApplication app) { this.context = app; } private Context context; @Inject CurrencyService currencyService; /** * Formats the amount in TextView with the given currency preferences. * * @param view TextView to set the amount * @param amount to be formatted * @param currencyId Id currency to be formatted */ public void formatAmountTextView(TextView view, Money amount, Integer currencyId) { if (amount == null) { Timber.w("Amount for formatting is null."); return; } String displayText; CurrencyService currencyService = getCurrencyService(); if (currencyId == null) { displayText = currencyService.getBaseCurrencyFormatted(amount); } else { displayText = currencyService.getCurrencyFormatted(currencyId, amount); } view.setText(displayText); view.setTag(amount); } /** * Uses the number of decimals from the base currency, separators from the app locale. * * @param amount Amount to be formatted. * @return String representation of the formatted number. */ public String formatWithLocale(Money amount) { // Use the number of decimals from the base currency. int scale = this.getScaleForBaseCurrency(); // separators from the locale. String decimalSeparator = getDecimalSeparatorForAppLocale(); String groupSeparator = getGroupingSeparatorForAppLocale(); return format(amount, scale, decimalSeparator, groupSeparator); } public Context getContext() { return this.context; } public int getScaleForBaseCurrency() { CurrencyService service = getCurrencyService(); Currency baseCurrency = service.getBaseCurrency(); if (baseCurrency == null) { ExceptionHandler handler = new ExceptionHandler(this.context, this); handler.showMessage(context.getString(R.string.base_currency_not_set)); return Constants.DEFAULT_PRECISION; } int scale = baseCurrency.getScale(); // int decimals = this.numericHelper.getNumberOfDecimals(scale); return scale; } public String getDecimalSeparatorForAppLocale() { Locale locale = MoneyManagerApplication.getApp().getAppLocale(); DecimalFormat currencyFormatter = (DecimalFormat) NumberFormat.getInstance(locale); char decimalSeparator = currencyFormatter.getDecimalFormatSymbols().getDecimalSeparator(); String separator = Character.toString(decimalSeparator); return separator; } public String getGroupingSeparatorForAppLocale() { Locale locale = MoneyManagerApplication.getApp().getAppLocale(); DecimalFormat currencyFormatter = (DecimalFormat) NumberFormat.getInstance(locale); char groupingSeparator = currencyFormatter.getDecimalFormatSymbols().getGroupingSeparator(); String separator = Character.toString(groupingSeparator); return separator; } public String format(Money value, String numberFormat) { // DecimalFormat format = new DecimalFormat(numberFormat); DecimalFormat formatter = new DecimalFormat(numberFormat); return formatter.format(value.toDouble()); } /** * Formats the amount with the currency scale, decimal & group separators, prefix and suffix. * * @param value value to format * @param showSymbols Whether to include the currency symbol in the output. * @return formatted value */ public String format(Money value, boolean showSymbols, Currency currency) { if (currency == null) return "n/a"; String result = this.format(value, currency.getScale(), currency.getDecimalSeparator(), currency.getGroupSeparator()); // check suffix if ((showSymbols) && (!TextUtils.isEmpty(currency.getSfxSymbol()))) { result = result + " " + currency.getSfxSymbol(); } // check prefix if (((showSymbols) && !TextUtils.isEmpty(currency.getPfxSymbol()))) { result = currency.getPfxSymbol() + " " + result; } return result; } /** * Formats the given value with the currency preferences. * @param value value to format * @return value formatted */ public String format(Money value, Currency currency) { return format(value, true, currency); } public String format(Money value, int currencyId) { CurrencyService currencyService = getCurrencyService(); Currency currency = currencyService.getCurrency(currencyId); return format(value, true, currency); } public String format(Money value, int scale, String decimalSeparator, String groupSeparator) { int decimals = new NumericHelper(getContext()).getNumberOfDecimals(scale); value = value.truncate(decimals); // set format DecimalFormatSymbols formatSymbols = new DecimalFormatSymbols(); // getDecimalSeparator() if (!(TextUtils.isEmpty(decimalSeparator))) { formatSymbols.setDecimalSeparator(decimalSeparator.charAt(0)); } // getGroupSeparator() if (!(TextUtils.isEmpty(groupSeparator))) { formatSymbols.setGroupingSeparator(groupSeparator.charAt(0)); } // All these use locale-dependent formatting. // DecimalFormat formatter = new DecimalFormat(); // Locale appLocale = MoneyManagerApplication.getInstance().getLocale(); // DecimalFormat formatter = (DecimalFormat) NumberFormat.getNumberInstance(appLocale); String pattern = NumericPatternGenerator.getPattern(decimals); DecimalFormat formatter = new DecimalFormat(pattern); formatter.setMaximumFractionDigits(decimals); formatter.setMinimumFractionDigits(decimals); formatter.setGroupingSize(3); formatter.setDecimalFormatSymbols(formatSymbols); String result = formatter.format(value.toDouble()); return result; } /** * Ultimately, all the methods should converge to this one. Provides customization options for * the amount. * * @param amount Amount to be formatted * @param decimals Number of decimals to use. * @param decimalSeparator Decimal separator character. * @param groupSeparator Group separator character. * @param prefix the prefix to attach. * @param suffix the suffix to attach. * @return Number formatted. */ public String formatNumber(Money amount, int decimals, String decimalSeparator, String groupSeparator, String prefix, String suffix) { // Decimals String pattern = NumericPatternGenerator.getPattern(decimals); DecimalFormat formatter = new DecimalFormat(pattern); formatter.setMaximumFractionDigits(decimals); formatter.setMinimumFractionDigits(decimals); // Separators DecimalFormatSymbols formatSymbols = new DecimalFormatSymbols(); if (!(TextUtils.isEmpty(decimalSeparator))) { formatSymbols.setDecimalSeparator(decimalSeparator.charAt(0)); } if (!(TextUtils.isEmpty(groupSeparator))) { formatSymbols.setGroupingSeparator(groupSeparator.charAt(0)); } // Group size formatter.setGroupingSize(3); formatter.setDecimalFormatSymbols(formatSymbols); String result = formatter.format(amount.toDouble()); // Currency symbol, prefix/suffix if (prefix != null) { result = prefix + result; } if (suffix != null) { result += suffix; } return result; } /** * Formats the number by ignoring the decimal count. * Group & decimal symbols and currency prefix/suffix are used. * * @param amount * @param currencyId * @return */ public String formatNumberIgnoreDecimalCount(Money amount, int currencyId) { if (currencyId == Constants.NOT_SET) { // use locale values? return formatWithLocale(amount); } // number of decimals - do not modify int scale = Constants.DEFAULT_PRECISION; Currency currency = getCurrencyService().getCurrency(currencyId); // group & decimal symbols // currency symbol return this.formatNumber(amount, scale, currency.getDecimalSeparator(), currency.getGroupSeparator(), currency.getPfxSymbol(), currency.getSfxSymbol()); } public CurrencyService getCurrencyService() { if (this.currencyService == null) { this.currencyService = new CurrencyService(getContext()); } return this.currencyService; } public String getValueFormattedInBaseCurrency(Money value) { CurrencyService service = getCurrencyService(); return format(value, service.getBaseCurrency()); } }