/*
* 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.account;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import com.money.manager.ex.Constants;
import com.money.manager.ex.R;
import com.money.manager.ex.common.Calculator;
import com.money.manager.ex.common.CalculatorActivity;
import com.money.manager.ex.common.MmxBaseFragmentActivity;
import com.money.manager.ex.core.Core;
import com.money.manager.ex.core.FormatUtilities;
import com.money.manager.ex.core.MenuHelper;
import com.money.manager.ex.core.RequestCodes;
import com.money.manager.ex.currency.list.CurrencyListActivity;
import com.money.manager.ex.currency.CurrencyRepository;
import com.money.manager.ex.currency.CurrencyService;
import com.money.manager.ex.datalayer.AccountRepository;
import com.money.manager.ex.domainmodel.Account;
import com.money.manager.ex.domainmodel.Currency;
import com.money.manager.ex.settings.AppSettings;
import org.parceler.Parcels;
import java.util.Arrays;
import icepick.State;
import info.javaperformance.money.Money;
import info.javaperformance.money.MoneyFactory;
/**
* Edit Account activity/form
*/
public class AccountEditActivity
extends MmxBaseFragmentActivity {
public static final String KEY_ACCOUNT_ENTITY = "AccountEditActivity:AccountEntity";
public static final String KEY_ACCOUNT_ID = "AccountEditActivity:AccountId";
public static final String KEY_CURRENCY_NAME = "AccountEditActivity:CurrencyName";
public static final String KEY_SYMBOL = "AccountEditActivity:Symbol";
public static final String KEY_DEFAULT_ACCOUNT = "AccountEditActivity:DefaultAccount";
private static final String KEY_ACTION = "AccountEditActivity:Action";
// Constant
private static final int PLUS = 0;
private static final int MINUS = 1;
private Account mAccount;
// Action type
private String mIntentAction = Intent.ACTION_INSERT; // Insert? Edit?
// Activity members
@State String mCurrencyName;
private String[] mAccountTypeValues;
private String[] mAccountStatusValues;
private AccountEditViewHolder mViewHolder;
@State boolean mIsDefault;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// create a dummy account for initial values
mAccount = Account.create("", AccountTypes.CASH, AccountStatuses.OPEN, false, Constants.NOT_SET);
// Restore saved instance state
if ((savedInstanceState != null)) {
restoreInstanceState(savedInstanceState);
}
// Get Intent extras
if (getIntent() != null && savedInstanceState == null) {
mIntentAction = getIntent().getAction();
if (mIntentAction != null && Intent.ACTION_EDIT.equals(getIntent().getAction())) {
int accountId = getIntent().getIntExtra(KEY_ACCOUNT_ID, Constants.NOT_SET);
if (accountId != Constants.NOT_SET) {
// Load account or exit if one not found
if (!loadAccount(accountId)) {
finish();
return;
}
}
}
}
// default currency
if (mAccount.getCurrencyId() == Constants.NOT_SET) {
CurrencyService currencyService = new CurrencyService(getApplicationContext());
Currency baseCurrency = currencyService.getBaseCurrency();
if (baseCurrency != null) {
mAccount.setCurrencyId(baseCurrency.getCurrencyId());
mCurrencyName = baseCurrency.getName();
}
}
// Default account
AppSettings settings = new AppSettings(this);
Integer defaultAccountId = settings.getGeneralSettings().getDefaultAccountId();
mIsDefault = mAccount.getId().equals(defaultAccountId);
// Compose layout
setContentView(R.layout.activity_edit_account);
// showStandardToolbarActions();
setDisplayHomeAsUpEnabled(true);
initializeControls();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != Activity.RESULT_OK) return;
switch (requestCode) {
case RequestCodes.CURRENCY:
if (data == null) return;
int currencyId = data.getIntExtra(CurrencyListActivity.INTENT_RESULT_CURRENCYID, Constants.NOT_SET);
mAccount.setCurrencyId(currencyId);
mCurrencyName = data.getStringExtra(CurrencyListActivity.INTENT_RESULT_CURRENCYNAME);
refreshCurrencyName();
// refresh amount
Money initialBalance = mAccount.getInitialBalance();
if (initialBalance != null) {
refreshAmount(initialBalance);
}
break;
case RequestCodes.AMOUNT:
String stringExtra = data.getStringExtra(CalculatorActivity.RESULT_AMOUNT);
Money amount = MoneyFactory.fromString(stringExtra);
refreshAmount(amount);
break;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
new MenuHelper(this, menu).addSaveToolbarIcon();
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case MenuHelper.save:
return onActionDoneClick();
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Get members values from controls
collectInput();
// Save the state.
outState.putParcelable(KEY_ACCOUNT_ENTITY, Parcels.wrap(mAccount));
// outState.putString(KEY_CURRENCY_NAME, mCurrencyName);
// outState.putBoolean(KEY_DEFAULT_ACCOUNT, mIsDefault);
outState.putString(KEY_ACTION, mIntentAction);
}
@Override
public boolean onActionCancelClick() {
finish();
// return super.onActionCancelClick();
return true;
}
@Override
public boolean onActionDoneClick() {
if (saveAccount()) {
// If everything is okay, finish the activity
finish();
return true;
} else {
return false;
}
}
/**
* Refresh current currency name on controls
*/
public void refreshCurrencyName() {
// write currency into text button
if (!(TextUtils.isEmpty(mCurrencyName))) {
mViewHolder.txtSelectCurrency.setText(mCurrencyName);
} else {
mViewHolder.txtSelectCurrency.setText(getResources().getString(R.string.select_currency));
}
}
// Private
/**
* Transfer data from UI to the model.
* Replace with data binding later.
*/
private void collectInput() {
mAccount.setName(mViewHolder.edtAccountName.getText().toString());
AccountTypes accountType = getSelectedAccountType();
mAccount.setType(accountType);
mAccount.setAccountNumber(mViewHolder.edtAccountNumber.getText().toString());
mAccount.setHeldAt(mViewHolder.edtAccountHeldAt.getText().toString());
mAccount.setWebSite(mViewHolder.webSiteEditText.getText().toString());
mAccount.setContactInfo(mViewHolder.edtContact.getText().toString());
mAccount.setAccessInfo(mViewHolder.edtAccessInfo.getText().toString());
mAccount.setNotes(mViewHolder.edtNotes.getText().toString());
if (mViewHolder.spinSymbolInitialBalance.getSelectedItemPosition() != PLUS) {
Money initialBalance = mAccount.getInitialBalance();
initialBalance = initialBalance.negate();
mAccount.setInitialBalance(initialBalance);
}
}
private void displayDefaultAccount() {
mViewHolder.defaultAccountCheckbox.setChecked(mIsDefault);
}
private void displayFavouriteStatus() {
mViewHolder.imageViewAccountFav.setTag(mAccount.getFavorite().toString());
int imageResource = mAccount.getFavorite()
? R.string.ic_star
: R.string.ic_star_outline;
mViewHolder.imageViewAccountFav.setText(imageResource);
}
private AccountTypes getSelectedAccountType() {
int accountTypePosition = mViewHolder.accountTypeSpinner.getSelectedItemPosition();
String accountTypeName = mAccountTypeValues[accountTypePosition];
AccountTypes accountType = AccountTypes.get(accountTypeName);
return accountType;
}
private void initializeControls() {
mViewHolder = new AccountEditViewHolder(this);
// Initial balance.
ArrayAdapter<String> adapterSymbol = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, new String[]{"+", "-"});
mViewHolder.spinSymbolInitialBalance.setAdapter(adapterSymbol);
mViewHolder.txtInitialBalance.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Calculator.forActivity(AccountEditActivity.this)
.currency(mAccount.getCurrencyId())
.amount(mAccount.getInitialBalance())
.show(RequestCodes.AMOUNT);
}
});
// Account Type adapters and values
String[] mAccountTypeItems = getResources().getStringArray(R.array.accounttype_items);
mAccountTypeValues = AccountTypes.getNames();
ArrayAdapter<String> adapterAccountType = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, mAccountTypeItems);
adapterAccountType.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mViewHolder.accountTypeSpinner.setAdapter(adapterAccountType);
if (!(TextUtils.isEmpty(mAccount.getTypeName()))) {
if (Arrays.asList(mAccountTypeValues).indexOf(mAccount.getTypeName()) >= 0) {
int position = Arrays.asList(mAccountTypeValues).indexOf(mAccount.getTypeName());
mViewHolder.accountTypeSpinner.setSelection(position, true);
}
} else {
AccountTypes accountType = getSelectedAccountType();
mAccount.setType(accountType);
}
// Account Status adapters and values
String[] mAccountStatusItems = getResources().getStringArray(R.array.accountstatus_items);
mAccountStatusValues = getResources().getStringArray(R.array.accountstatus_values);
ArrayAdapter<String> adapterAccountStatus = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, mAccountStatusItems);
mViewHolder.spinAccountStatus.setAdapter(adapterAccountStatus);
adapterAccountStatus.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
if (!(TextUtils.isEmpty(mAccount.getStatus()))) {
if (Arrays.asList(mAccountStatusValues).indexOf(mAccount.getStatus()) >= 0) {
mViewHolder.spinAccountStatus.setSelection(Arrays.asList(mAccountStatusValues).indexOf(mAccount.getStatus()), true);
}
} else {
String selectedStatus = (String) mViewHolder.spinAccountStatus.getSelectedItem();
AccountStatuses status = AccountStatuses.get(selectedStatus);
mAccount.setStatus(status);
}
// Set up control listeners
initializeDefaultAccountControls();
mViewHolder.accountTypeSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if ((position >= 0) && (position <= mAccountTypeValues.length)) {
//ArrayAdapter<String> adapter = (ArrayAdapter<String>) parent.getAdapter();
String accountTypeValue = mAccountTypeValues[position];
AccountTypes accountType = AccountTypes.get(accountTypeValue);
mAccount.setType(accountType);
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
mViewHolder.spinAccountStatus.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if ((position >= 0) && (position <= mAccountStatusValues.length)) {
String selectedStatus = mAccountStatusValues[position];
AccountStatuses status = AccountStatuses.get(selectedStatus);
mAccount.setStatus(status);
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
// Favourite
initializeFavouriteAccountControls();
mViewHolder.txtSelectCurrency.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(AccountEditActivity.this, CurrencyListActivity.class);
intent.setAction(Intent.ACTION_PICK);
startActivityForResult(intent, RequestCodes.CURRENCY);
}
});
// Display data.
displayAccountValues();
// Refresh data on the other controls
refreshCurrencyName();
}
private void displayAccountValues() {
if (!(TextUtils.isEmpty(mAccount.getName()))) {
mViewHolder.edtAccountName.setText(mAccount.getName());
}
// Default account.
displayDefaultAccount();
// Favourite account.
displayFavouriteStatus();
// Initial balance
mViewHolder.spinSymbolInitialBalance.setSelection(mAccount.getInitialBalance().toDouble() >= 0 ? PLUS : MINUS);
// always use positive numeric value. The sign is in the spinner.
if (mAccount.getInitialBalance().toDouble() < 0) {
mAccount.setInitialBalance(mAccount.getInitialBalance().negate());
}
FormatUtilities formatter = new FormatUtilities(this);
formatter.formatAmountTextView(mViewHolder.txtInitialBalance, mAccount.getInitialBalance(), mAccount.getCurrencyId());
// Account Number
if (!(TextUtils.isEmpty(mAccount.getAccountNumber()))) {
mViewHolder.edtAccountNumber.setText(mAccount.getAccountNumber());
}
if (!(TextUtils.isEmpty(mAccount.getHeldAt()))) {
mViewHolder.edtAccountHeldAt.setText(mAccount.getHeldAt());
}
if (!(TextUtils.isEmpty(mAccount.getWebSite()))) {
mViewHolder.webSiteEditText.setText(mAccount.getWebSite());
}
if (!(TextUtils.isEmpty(mAccount.getContactInfo()))) {
mViewHolder.edtContact.setText(mAccount.getContactInfo());
}
if (!(TextUtils.isEmpty(mAccount.getAccessInfo()))) {
mViewHolder.edtAccessInfo.setText(mAccount.getAccessInfo());
}
// Notes
if (!(TextUtils.isEmpty(mAccount.getNotes()))) {
mViewHolder.edtNotes.setText(mAccount.getNotes());
}
}
private void initializeDefaultAccountControls() {
mViewHolder.defaultAccountCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mIsDefault = isChecked;
displayDefaultAccount();
}
});
mViewHolder.defaultAccountText.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mIsDefault = !mIsDefault;
displayDefaultAccount();
}
});
}
private void initializeFavouriteAccountControls() {
OnClickListener listener = new OnClickListener() {
@Override
public void onClick(View v) {
mAccount.setFavorite(!mAccount.getFavorite());
displayFavouriteStatus();
}
};
mViewHolder.imageViewAccountFav.setOnClickListener(listener);
mViewHolder.favouriteAccountTextView.setOnClickListener(listener);
}
private void refreshAmount(Money amount) {
mAccount.setInitialBalance(amount);
FormatUtilities formatter = new FormatUtilities(this);
formatter.formatAmountTextView(mViewHolder.txtInitialBalance, amount, mAccount.getCurrencyId());
}
/**
* update data into database
* @return true if update data successful
*/
private boolean saveAccount() {
collectInput();
if (!validateData()) {
return false;
}
AccountRepository repo = new AccountRepository(this);
repo.save(mAccount);
saveDefaultAccount();
return true;
}
/**
* Select the account identified by accountId
* @param accountId account id
* @return true if data is correctly selected, false if error occurs
*/
private boolean loadAccount(int accountId) {
AccountRepository repository = new AccountRepository(getApplicationContext());
mAccount = repository.load(accountId);
if (mAccount == null) return false;
// TODO Select currency name: could be improved for better usage of members
selectCurrencyName(mAccount.getCurrencyId());
return true;
}
private void restoreInstanceState(Bundle savedInstanceState) {
Account restored = Parcels.unwrap(savedInstanceState.getParcelable(KEY_ACCOUNT_ENTITY));
if (restored != null) {
mAccount = restored;
if (savedInstanceState.getInt(KEY_SYMBOL) == MINUS) {
mAccount.setInitialBalance(mAccount.getInitialBalance().negate());
}
}
// mCurrencyName = savedInstanceState.getString(KEY_CURRENCY_NAME);
// mIsDefault = savedInstanceState.getBoolean(KEY_DEFAULT_ACCOUNT);
mIntentAction = savedInstanceState.getString(KEY_ACTION);
}
/**
* Select info for current currency
* @param currencyId Id of the currency to select
* @return A boolean indicating whether the retrieval of currency name was successful.
*/
private boolean selectCurrencyName(int currencyId) {
boolean result;
CurrencyRepository repository = new CurrencyRepository(getApplicationContext());
Currency currency = repository.loadCurrency(currencyId);
if (currency == null) {
mCurrencyName = "N/A";
result = false;
} else {
mCurrencyName = currency.getName();
result = true;
}
return result;
}
private void saveDefaultAccount() {
AppSettings settings = new AppSettings(AccountEditActivity.this);
if (mIsDefault) {
// set this account as default.
settings.getGeneralSettings().setDefaultAccountId(mAccount.getId());
} else {
// Check if this was the default account and is now being unset.
Integer currentDefaultAccountId = settings.getGeneralSettings().getDefaultAccountId();
if (currentDefaultAccountId != null && currentDefaultAccountId.equals(mAccount.getId())) {
// Reset default account.
settings.getGeneralSettings().setDefaultAccountId(null);
}
}
}
/**
* Validate entered data.
*/
private boolean validateData() {
Core core = new Core(this);
if (mAccount.getCurrencyId() == null || mAccount.getCurrencyId() == Constants.NOT_SET) {
core.alert(R.string.error_currency_not_selected);
return false;
}
if (!mAccount.hasInitialBalance()) {
core.alert(R.string.error_initialbal_empty);
return false;
}
if (TextUtils.isEmpty(mAccount.getName())) {
core.alert(R.string.error_accountname_empty);
return false;
}
if (TextUtils.isEmpty(mAccount.getTypeName())) {
core.alert(R.string.error_accounttype_empty);
return false;
}
if (TextUtils.isEmpty(mAccount.getStatus())) {
core.alert(R.string.error_status_empty);
return false;
}
// TODO: Should throw an exception in case favoriteacct is not in {'TRUE', 'FALSE'}
return true;
}
}