/*
* Copyright (C) 2010 Nullbyte <http://nullbyte.eu>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.liato.bankdroid;
import com.google.common.collect.Iterators;
import com.crashlytics.android.Crashlytics;
import com.liato.bankdroid.api.configuration.Entry;
import com.liato.bankdroid.api.configuration.Field;
import com.liato.bankdroid.appwidget.AutoRefreshService;
import com.liato.bankdroid.banking.Account;
import com.liato.bankdroid.banking.Bank;
import com.liato.bankdroid.banking.BankChoice;
import com.liato.bankdroid.banking.BankFactory;
import com.liato.bankdroid.banking.exceptions.BankChoiceException;
import com.liato.bankdroid.banking.exceptions.BankException;
import com.liato.bankdroid.banking.exceptions.LoginException;
import com.liato.bankdroid.configuration.DefaultConnectionConfiguration;
import com.liato.bankdroid.db.DBAdapter;
import com.liato.bankdroid.utils.FieldTypeMapper;
import com.liato.bankdroid.utils.NetworkUtils;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.method.PasswordTransformationMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.OnClick;
import timber.log.Timber;
public class BankEditActivity extends LockableActivity implements OnItemSelectedListener {
@InjectView(R.id.spnBankeditBanklist)
Spinner mBankSpinner;
@InjectView(R.id.layoutBankConfiguration)
LinearLayout mFormContainer;
@InjectView(R.id.txtErrorDesc)
TextView mErrorDescription;
private Bank selectedBank;
private long bankId = -1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bank);
ButterKnife.inject(this);
this.getWindow()
.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
List<Bank> items = BankFactory.listBanks(this);
Collections.sort(items);
BankSpinnerAdapter<Bank> adapter = new BankSpinnerAdapter<>(this, items);
mBankSpinner.setAdapter(adapter);
Bundle extras = getIntent().getExtras();
if (extras != null) {
bankId = extras.getLong("id", -1);
if (bankId != -1) {
Bank bank = BankFactory.bankFromDb(bankId, this, false);
if (bank != null) {
mErrorDescription.setVisibility(
bank.isDisabled() ? View.VISIBLE : View.INVISIBLE);
mBankSpinner.setEnabled(false);
mBankSpinner.setSelection(adapter.getPosition(bank));
selectedBank = bank;
createForm(selectedBank.getConnectionConfiguration(),
DefaultConnectionConfiguration.fields()
);
populateForm(bank);
}
}
}
mBankSpinner.setOnItemSelectedListener(this);
}
@OnClick(R.id.btnSettingsOk)
public void onSubmit(View v) {
if (!validate()) {
return;
}
selectedBank.setProperties(getFormParameters(selectedBank.getConnectionConfiguration()));
selectedBank.setCustomName(getFormParameter(DefaultConnectionConfiguration.NAME));
selectedBank.setDbid(bankId);
new DataRetrieverTask(this, selectedBank).execute();
}
@OnClick(R.id.btnSettingsCancel)
public void onCancel(View v) {
this.finish();
}
@Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int pos, long id) {
Bank selectedBank = (Bank) parentView.getItemAtPosition(pos);
if (this.selectedBank == null || !this.selectedBank.equals(selectedBank)) {
this.selectedBank = selectedBank;
mFormContainer.removeAllViewsInLayout();
createForm(this.selectedBank.getConnectionConfiguration(),
DefaultConnectionConfiguration.fields()
);
}
}
@Override
public void onNothingSelected(AdapterView<?> arg) {
}
private void createForm(List<Field>... configurations) {
for (List<Field> fields : configurations) {
for (Field field : fields) {
createLabel(field);
if (field.getValues().isEmpty()) {
createField(field);
} else {
createSpinner(field);
}
}
}
}
private void createLabel(Field field) {
TextView fieldText = new TextView(this);
String label = field.getLabel() + (field.isRequired() ? "" : " " + getString(R.string.optional_field));
fieldText.setText(label);
fieldText.setVisibility(field.isHidden() ? View.GONE : View.VISIBLE);
mFormContainer.addView(fieldText);
}
private void createField(Field field) {
EditText inputField = new EditText(this);
inputField.setHint(field.getPlaceholder());
if (field.isSecret()) {
inputField.setTransformationMethod(
PasswordTransformationMethod.getInstance());
} else {
inputField
.setInputType(FieldTypeMapper.fromFieldType(field.getFieldType()));
}
inputField.setVisibility(field.isHidden() ? View.GONE : View.VISIBLE);
inputField.setTag(field.getReference());
mFormContainer.addView(inputField);
}
private void createSpinner(Field field) {
Spinner spinner = new Spinner(this);
spinner.setAdapter(new ArrayAdapter<Entry>(this, android.R.layout.simple_spinner_item,
field.getValues()));
spinner.setTag(field.getReference());
mFormContainer.addView(spinner);
}
private void populateForm(Bank bank) {
EditText customName = (EditText) mFormContainer.findViewWithTag(
DefaultConnectionConfiguration.NAME);
customName.setText(bank.getCustomName());
for (Map.Entry<String, String> property : bank.getProperties().entrySet()) {
EditText propertyInput = (EditText) mFormContainer.findViewWithTag(property.getKey());
propertyInput.setText(property.getValue());
}
}
private Map<String, String> getFormParameters(List<Field> fields) {
Map<String, String> properties = new HashMap<>();
for (Field field : fields) {
properties.put(field.getReference(), getFormParameter(field.getReference()));
}
return properties;
}
private String getFormParameter(String property) {
View propertyView = mFormContainer.findViewWithTag(property);
if (propertyView instanceof EditText) {
EditText propertyInput = (EditText) propertyView;
return propertyInput.getText().toString().trim();
} else if (propertyView instanceof Spinner) {
Spinner spinnerProperty = (Spinner) propertyView;
Entry entry = (Entry) spinnerProperty.getSelectedItem();
return entry.getKey();
} else {
return null;
}
}
private boolean validate() {
boolean valid = true;
Iterator<Field> fields = Iterators.concat(selectedBank.getConnectionConfiguration().iterator(),
DefaultConnectionConfiguration.fields().iterator());
while (fields.hasNext()) {
Field field = fields.next();
try {
field.validate(getFormParameter(field.getReference()));
} catch (IllegalArgumentException e) {
valid = false;
((EditText) mFormContainer.findViewWithTag(field.getReference())).setError(e.getMessage());
}
}
return valid;
}
private class BankSpinnerAdapter<T> extends ArrayAdapter<T> {
private LayoutInflater inflater;
public BankSpinnerAdapter(Context context, List<T> items) {
super(context, R.layout.bank_spinner_item, R.id.txtBank, items);
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.bank_spinner_item, parent, false);
}
((TextView) convertView.findViewById(R.id.txtBank))
.setText(((Bank) getItem(position)).getName());
((ImageView) convertView.findViewById(R.id.imgBank))
.setImageResource(((Bank) getItem(position)).getImageResource());
return convertView;
}
@Override
public View getDropDownView(int position, View convertView,
ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.bank_spinner_dropdown_item, parent, false);
}
((TextView) convertView.findViewById(R.id.txtBank))
.setText(((Bank) getItem(position)).getName());
((ImageView) convertView.findViewById(R.id.imgBank))
.setImageResource(((Bank) getItem(position)).getImageResource());
return convertView;
}
}
private class DataRetrieverTask extends AsyncTask<String, Void, Void> {
private final ProgressDialog dialog = new ProgressDialog(BankEditActivity.this);
private Exception exc = null;
private Bank bank;
private BankEditActivity context;
private Resources res;
public DataRetrieverTask(BankEditActivity context, Bank bank) {
this.context = context;
this.res = context.getResources();
this.bank = bank;
}
protected void onPreExecute() {
this.dialog.setMessage(res.getText(R.string.logging_in));
this.dialog.show();
}
protected Void doInBackground(final String... args) {
try {
bank.update();
bank.updateAllTransactions();
bank.closeConnection();
DBAdapter.save(bank, context);
// Transactions updated.
final SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(getBaseContext());
if (prefs.getBoolean("content_provider_enabled", false)) {
final ArrayList<Account> accounts = bank.getAccounts();
for (final Account account : accounts) {
AutoRefreshService.broadcastTransactionUpdate(
getBaseContext(), bank.getDbId(),
account.getId());
}
}
} catch (BankException e) {
this.exc = e;
Crashlytics.logException(e);
} catch (LoginException e) {
this.exc = e;
} catch (BankChoiceException e) {
this.exc = e;
} catch (IOException e) {
this.exc = e;
if (NetworkUtils.isInternetAvailable()) {
Crashlytics.logException(e);
}
}
return null;
}
protected void onPostExecute(final Void unused) {
AutoRefreshService.sendWidgetRefresh(context);
ActivityHelper.dismissDialog(this.dialog);
if (this.exc != null) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
if (this.exc instanceof BankChoiceException) {
final BankChoiceException e = (BankChoiceException) exc;
final String[] items = new String[e.getBanks().size()];
int i = 0;
for (BankChoice b : e.getBanks()) {
items[i] = b.getName();
i++;
}
builder.setTitle(R.string.select_a_bank);
builder.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
selectedBank.setExtras(e.getBanks().get(item).getId());
new DataRetrieverTask(context, selectedBank).execute();
}
});
} else {
Timber.w(exc, "Failed getting info from bank");
builder.setMessage(this.exc.getMessage())
.setTitle(res.getText(R.string.could_not_create_account))
.setIcon(android.R.drawable.ic_dialog_alert)
.setNeutralButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
}
AlertDialog alert = builder.create();
if (!context.isFinishing()) {
alert.show();
}
} else {
context.finish();
}
}
}
}