package com.code44.finance.ui.currencies;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListAdapter;
import android.widget.ListPopupWindow;
import android.widget.TextView;
import com.code44.finance.R;
import com.code44.finance.api.currencies.CurrenciesApi;
import com.code44.finance.api.currencies.ExchangeRateRequest;
import com.code44.finance.common.model.DecimalSeparator;
import com.code44.finance.common.model.GroupSeparator;
import com.code44.finance.common.model.SymbolPosition;
import com.code44.finance.data.DataStore;
import com.code44.finance.data.db.Tables;
import com.code44.finance.data.model.Currency;
import com.code44.finance.data.providers.CurrenciesProvider;
import com.code44.finance.qualifiers.Main;
import com.code44.finance.ui.common.ModelEditActivity;
import com.code44.finance.utils.MoneyFormatter;
import com.code44.finance.utils.analytics.Analytics;
import com.squareup.otto.Subscribe;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import javax.inject.Inject;
import fr.castorflex.android.smoothprogressbar.SmoothProgressBar;
import fr.castorflex.android.smoothprogressbar.SmoothProgressDrawable;
public class CurrencyEditActivity extends ModelEditActivity<Currency> implements View.OnClickListener, CompoundButton.OnCheckedChangeListener {
private static final int LOADER_CURRENCIES = 1;
private final Set<String> existingCurrencyCodes = new HashSet<>();
@Inject CurrenciesApi currenciesApi;
@Inject @Main Currency mainCurrency;
private SmoothProgressBar loadingView;
private AutoCompleteTextView codeEditTextView;
private Button thousandsSeparatorButton;
private Button decimalSeparatorButton;
private Button decimalsCountButton;
private TextView codeTextView;
private TextView symbolTextView;
private EditText symbolEditTextView;
private Button symbolPositionButton;
private EditText exchangeRateEditTextView;
private ListPopupWindow listPopupWindow;
private View mainCurrencyContainerView;
private View exchangeRateContainerView;
private CheckBox isDefaultCheckBox;
public static void start(Context context, String currencyId) {
startActivity(context, makeIntent(context, CurrencyEditActivity.class, currencyId));
}
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportLoaderManager().initLoader(LOADER_CURRENCIES, null, this);
}
@Override public void onResume() {
super.onResume();
setRefreshing(false);
getEventBus().register(this);
}
@Override public void onPause() {
super.onPause();
getEventBus().unregister(this);
}
@Override protected boolean onSave(Currency model) {
boolean canSave = true;
if (TextUtils.isEmpty(model.getCode()) || model.getCode().length() != 3) {
canSave = false;
// TODO Show error
}
if (canSave) {
DataStore.insert().values(model.asValues()).into(this, CurrenciesProvider.uriCurrencies());
}
return canSave;
}
@Override protected void ensureModelUpdated(Currency model) {
model.setCode(codeEditTextView.getText().toString());
model.setSymbol(symbolEditTextView.getText().toString());
double exchangeRate;
try {
exchangeRate = Double.parseDouble(exchangeRateEditTextView.getText().toString());
} catch (Exception e) {
exchangeRate = 1.0;
}
model.setExchangeRate(exchangeRate);
}
@Override protected CursorLoader getModelCursorLoader(String modelId) {
return Tables.Currencies.getQuery().asCursorLoader(this, CurrenciesProvider.uriCurrency(modelId));
}
@Override protected Currency getModelFrom(Cursor cursor) {
return Currency.from(cursor);
}
@Override protected void onModelLoaded(Currency model) {
symbolEditTextView.setText(model.getSymbol());
codeEditTextView.setText(model.getCode());
thousandsSeparatorButton.setText(getGroupSeparatorExplanation(model.getGroupSeparator()));
decimalSeparatorButton.setText(getDecimalSeparatorExplanation(model.getDecimalSeparator()));
decimalsCountButton.setText(String.valueOf(model.getDecimalCount()));
exchangeRateEditTextView.setText(String.valueOf(model.getExchangeRate()));
isDefaultCheckBox.setChecked(model.isDefault());
updateFormatView();
updateCodeTitlePosition();
updateSymbolTitlePosition();
codeEditTextView.setEnabled(isNewModel());
mainCurrencyContainerView.setVisibility(mainCurrency.getId().equals(model.getId()) ? View.GONE : View.VISIBLE);
exchangeRateContainerView.setVisibility(model.isDefault() ? View.GONE : View.VISIBLE);
}
@Override public Loader<Cursor> onCreateLoader(int id, Bundle args) {
if (id == LOADER_CURRENCIES) {
return Tables.Currencies.getQuery().asCursorLoader(this, CurrenciesProvider.uriCurrencies());
}
return super.onCreateLoader(id, args);
}
@Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if (loader.getId() == LOADER_CURRENCIES) {
existingCurrencyCodes.clear();
if (data.moveToFirst()) {
do {
existingCurrencyCodes.add(data.getString(0));
} while (data.moveToNext());
}
return;
}
super.onLoadFinished(loader, data);
}
@Override protected int getLayoutId() {
return R.layout.activity_currency_edit;
}
@Override protected void onViewCreated(Bundle savedInstanceState) {
super.onViewCreated(savedInstanceState);
// Get view
loadingView = (SmoothProgressBar) findViewById(R.id.loadingView);
codeEditTextView = (AutoCompleteTextView) findViewById(R.id.codeEditTextView);
thousandsSeparatorButton = (Button) findViewById(R.id.thousandsSeparatorButton);
decimalSeparatorButton = (Button) findViewById(R.id.decimalSeparatorButton);
decimalsCountButton = (Button) findViewById(R.id.decimalsCountButton);
codeTextView = (TextView) findViewById(R.id.codeTextView);
symbolTextView = (TextView) findViewById(R.id.symbolTextView);
symbolEditTextView = (EditText) findViewById(R.id.symbolEditTextView);
symbolPositionButton = (Button) findViewById(R.id.symbolPositionButton);
exchangeRateEditTextView = (EditText) findViewById(R.id.exchangeRateEdit);
mainCurrencyContainerView = findViewById(R.id.mainCurrencyContainerView);
exchangeRateContainerView = findViewById(R.id.exchangeRateContainerView);
isDefaultCheckBox = (CheckBox) findViewById(R.id.isDefaultCheckBox);
final TextView currentMainCurrency_TV = (TextView) findViewById(R.id.currentMainCurrencyTextView);
final ImageButton refreshRateButton = (ImageButton) findViewById(R.id.refreshRateButton);
// Setup
prepareCurrenciesAutoComplete();
currentMainCurrency_TV.setText(getString(R.string.f_current_main_currency_is_x, mainCurrency.getCode()));
decimalsCountButton.setOnClickListener(this);
thousandsSeparatorButton.setOnClickListener(this);
decimalSeparatorButton.setOnClickListener(this);
symbolPositionButton.setOnClickListener(this);
isDefaultCheckBox.setOnCheckedChangeListener(this);
refreshRateButton.setOnClickListener(this);
refreshRateButton.setColorFilter(getResources().getColor(R.color.text_primary));
symbolEditTextView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
//noinspection ConstantConditions
model.setSymbol(symbolEditTextView.getText().toString());
updateFormatView();
updateSymbolTitlePosition();
}
@Override
public void afterTextChanged(Editable editable) {
}
});
codeEditTextView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
updateCodeTitlePosition();
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
@Override public void onCheckedChanged(CompoundButton checkBox, boolean isChecked) {
model.setDefault(isChecked);
onModelLoaded(model);
}
@Override public void onClick(View view) {
switch (view.getId()) {
case R.id.refreshRateButton: {
ensureModelUpdated(model);
final String code = model.getCode();
if (!TextUtils.isEmpty(code) && code.length() == 3) {
currenciesApi.updateExchangeRate(code, mainCurrency.getCode());
setRefreshing(true);
}
break;
}
case R.id.symbolPositionButton: {
final String[] values = new String[SymbolPosition.values().length];
int index = 0;
for (SymbolPosition symbolPosition : SymbolPosition.values()) {
values[index++] = getSymbolPositionExplanation(symbolPosition);
}
final ListAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, values);
final AdapterView.OnItemClickListener itemClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
listPopupWindow.dismiss();
listPopupWindow = null;
model.setSymbolPosition(SymbolPosition.values()[position]);
ensureModelUpdated(model);
onModelLoaded(model);
}
};
showPopupList(view, adapter, itemClickListener);
break;
}
case R.id.thousandsSeparatorButton: {
final String[] values = new String[GroupSeparator.values().length];
int index = 0;
for (GroupSeparator groupSeparator : GroupSeparator.values()) {
values[index++] = getGroupSeparatorExplanation(groupSeparator);
}
final ListAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, values);
final AdapterView.OnItemClickListener itemClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
listPopupWindow.dismiss();
listPopupWindow = null;
model.setGroupSeparator(GroupSeparator.values()[position]);
ensureModelUpdated(model);
onModelLoaded(model);
}
};
showPopupList(view, adapter, itemClickListener);
break;
}
case R.id.decimalSeparatorButton: {
final String[] values = new String[DecimalSeparator.values().length];
int index = 0;
for (DecimalSeparator decimalSeparator : DecimalSeparator.values()) {
values[index++] = getDecimalSeparatorExplanation(decimalSeparator);
}
final ListAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, values);
final AdapterView.OnItemClickListener itemClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
listPopupWindow.dismiss();
listPopupWindow = null;
model.setDecimalSeparator(DecimalSeparator.values()[position]);
ensureModelUpdated(model);
onModelLoaded(model);
}
};
showPopupList(view, adapter, itemClickListener);
break;
}
case R.id.decimalsCountButton: {
final ListAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, new String[]{"0", "1", "2"});
final AdapterView.OnItemClickListener itemClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
listPopupWindow.dismiss();
listPopupWindow = null;
model.setDecimalCount(position);
ensureModelUpdated(model);
onModelLoaded(model);
}
};
showPopupList(view, adapter, itemClickListener);
break;
}
}
}
@Override protected Analytics.Screen getScreen() {
return Analytics.Screen.CurrencyEdit;
}
@Subscribe public void onRefreshFinished(final ExchangeRateRequest request) {
if (model != null && model.getCode().equals(request.getFromCode())) {
loadingView.post(new Runnable() {
@Override public void run() {
setRefreshing(false);
final Currency currency = request.getCurrency();
if (currency != null) {
model.setExchangeRate(currency.getExchangeRate());
onModelLoaded(model);
}
}
});
}
}
private void prepareCurrenciesAutoComplete() {
// Build currencies set
final Set<java.util.Currency> currencySet = new HashSet<>();
final Locale[] locales = Locale.getAvailableLocales();
for (Locale loc : locales) {
try {
currencySet.add(java.util.Currency.getInstance(loc));
} catch (Exception exc) {
// Locale not found
}
}
// Build currencies codes array
final String[] currencies = new String[currencySet.size()];
int i = 0;
for (java.util.Currency currency : currencySet) {
currencies[i++] = currency.getCurrencyCode();
}
// Prepare auto complete view
final ArrayAdapter<String> autoCompleteAdapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, currencies);
codeEditTextView.setAdapter(autoCompleteAdapter);
codeEditTextView.setThreshold(0);
codeEditTextView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//noinspection ConstantConditions
checkForCurrencyDuplicate(codeEditTextView.getText().toString());
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
private void checkForCurrencyDuplicate(String code) {
if (isCurrencyExists(code) && isNewModel()) {
codeEditTextView.setError(getString(R.string.l_currency_exists));
} else {
codeEditTextView.setError(null);
}
}
private boolean isCurrencyExists(String code) {
return existingCurrencyCodes.contains(code.toUpperCase());
}
private void updateFormatView() {
symbolPositionButton.setText(MoneyFormatter.format(model, 100000, false));
}
private void showPopupList(View anchorView, ListAdapter adapter, AdapterView.OnItemClickListener itemClickListener) {
listPopupWindow = new ListPopupWindow(this);
listPopupWindow.setModal(true);
// listPopupWindow.setListSelector(getResources().getDrawable(R.drawable.btn_borderless));
listPopupWindow.setAdapter(adapter);
listPopupWindow.setOnItemClickListener(itemClickListener);
listPopupWindow.setAnchorView(anchorView);
listPopupWindow.show();
}
private void updateCodeTitlePosition() {
if (TextUtils.isEmpty(codeEditTextView.getText())) {
codeTextView.animate().translationY(codeEditTextView.getBaseline() + (codeTextView.getHeight() - codeTextView.getBaseline())).setDuration(100).start();
} else {
codeTextView.animate().translationY(0).setDuration(100).start();
}
}
private void updateSymbolTitlePosition() {
if (TextUtils.isEmpty(symbolEditTextView.getText())) {
symbolTextView.animate().translationY(symbolEditTextView.getBaseline() + (symbolTextView.getHeight() - symbolTextView.getBaseline())).setDuration(100).start();
} else {
symbolTextView.animate().translationY(0).setDuration(100).start();
}
}
private String getDecimalSeparatorExplanation(DecimalSeparator decimalSeparator) {
switch (decimalSeparator) {
case Dot:
return getString(R.string.dot);
case Comma:
return getString(R.string.comma);
case Space:
return getString(R.string.space);
}
return null;
}
private String getGroupSeparatorExplanation(GroupSeparator groupSeparator) {
switch (groupSeparator) {
case None:
return getString(R.string.none);
case Dot:
return getString(R.string.dot);
case Comma:
return getString(R.string.comma);
case Space:
return getString(R.string.space);
}
return null;
}
private String getSymbolPositionExplanation(SymbolPosition symbolPosition) {
switch (symbolPosition) {
case CloseRight:
return getString(R.string.close_right);
case FarRight:
return getString(R.string.far_right);
case CloseLeft:
return getString(R.string.close_left);
case FarLeft:
return getString(R.string.far_left);
}
return null;
}
private void setRefreshing(boolean refreshing) {
if (refreshing) {
loadingView.setVisibility(View.VISIBLE);
loadingView.progressiveStart();
} else {
loadingView.progressiveStop();
loadingView.setSmoothProgressDrawableCallbacks(new SmoothProgressDrawable.Callbacks() {
@Override public void onStop() {
loadingView.setSmoothProgressDrawableCallbacks(null);
loadingView.setVisibility(View.GONE);
}
@Override public void onStart() {
}
});
}
}
}