/* * MoneyBalance - Android-based calculator for tracking and balancing expenses * Copyright (C) 2012 Ingo van Lil <inguin@gmx.de> * * 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 ivl.android.moneybalance; import ivl.android.moneybalance.dao.CalculationDataSource; import ivl.android.moneybalance.dao.DataBaseHelper; import ivl.android.moneybalance.data.Calculation; import java.util.ArrayList; import java.util.Currency; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Set; import android.content.Intent; import android.content.res.Resources; import android.os.Bundle; import android.support.v4.view.WindowCompat; import android.support.v7.app.ActionBarActivity; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.Toast; public class CalculationEditorActivity extends ActionBarActivity { private static final int MIN_PERSONS = 2; private static final int MAX_PERSONS = 100; private EditText titleField; private Spinner currencyField; private LinearLayout personList; private class PersonView { public View view; public EditText nameField; public ImageView deleteButton; } private final List<PersonView> personViews = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR); setContentView(R.layout.calculation_editor); setTitle(R.string.new_calculation); titleField = (EditText) findViewById(R.id.calculation_title); currencyField = (Spinner) findViewById(R.id.calculation_currency); personList = (LinearLayout) findViewById(R.id.person_list); CurrencySpinnerAdapter adapter = new CurrencySpinnerAdapter(this); int selected = adapter.findItem(getDefaultCurrency()); currencyField.setAdapter(adapter); currencyField.setSelection(selected); if (savedInstanceState != null) { List<String> personNames = savedInstanceState.getStringArrayList("personNames"); if (personNames != null) { for (String personName : personNames) { PersonView view = addPersonRow(); view.nameField.setText(personName); } } } createOrDeletePersonRows(); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putStringArrayList("personNames", getPersonNames()); } private static Currency getDefaultCurrency() { Locale locale = Locale.getDefault(); return Currency.getInstance(locale); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.calculation_editor_options, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_save: doSave(); return true; default: return super.onOptionsItemSelected(item); } } private PersonView addPersonRow() { final View view = getLayoutInflater().inflate(R.layout.person_list_entry, personList, false); personList.addView(view); final PersonView personView = new PersonView(); personView.view = view; personView.nameField = (EditText) view.findViewById(R.id.person_name); personView.deleteButton = (ImageView) view.findViewById(R.id.delete_button); personViews.add(personView); personView.nameField.setId(-1); // do not restore in onRestoreInstanceState() personView.nameField.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void afterTextChanged(Editable s) { createOrDeletePersonRows(); } }); personView.nameField.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) createOrDeletePersonRows(); } }); personView.deleteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { deletePersonRow(personView); createOrDeletePersonRows(); } }); return personView; } private void deletePersonRow(PersonView row) { personList.removeView(row.view); personViews.remove(row); } private void createOrDeletePersonRows() { int numEmpty = 0; int i = 0; while (i < personViews.size() && personViews.size() >= 2) { PersonView personView = personViews.get(i++); String name = personView.nameField.getText().toString().trim(); if (name.length() == 0) { if (!personView.nameField.hasFocus()) { deletePersonRow(personView); i--; } else { numEmpty++; } } } while ((personViews.size() < MIN_PERSONS) || (numEmpty < 1 && personViews.size() < MAX_PERSONS)) { addPersonRow(); numEmpty++; } for (i = 0; i < personViews.size(); i++) { PersonView personView = personViews.get(i); boolean last = (i + 1 == personViews.size()); personView.deleteButton.setVisibility(last ? View.INVISIBLE : View.VISIBLE); } } private String getCalculationTitle() { return titleField.getText().toString().trim(); } private String getPersonName(int i) { PersonView personView = personViews.get(i); return personView.nameField.getText().toString().trim(); } private ArrayList<String> getPersonNames() { ArrayList<String> personNames = new ArrayList<>(); for (int i = 0; i < personViews.size(); i++) { String name = getPersonName(i); if (name.length() > 0) personNames.add(name); } return personNames; } private boolean validate() { final Resources res = getResources(); boolean valid = true; titleField.setError(null); for (PersonView personView : personViews) personView.nameField.setError(null); if (getCalculationTitle().length() == 0) { final String errRequired = res.getString(R.string.validate_required); titleField.setError(errRequired); valid = false; } Set<String> personNames = new HashSet<>(); for (int i = 0; i < personViews.size(); i++) { String name = getPersonName(i); if (name.length() > 0) { if (personNames.contains(name)) { PersonView personView = personViews.get(i); personView.nameField.setError(res.getString(R.string.validate_duplicate_name)); valid = false; } else { personNames.add(name); } } } if (valid && personNames.size() < MIN_PERSONS) { PersonView personView = personViews.get(personViews.size() - 1); String format = res.getString(R.string.validate_min_names); personView.nameField.setError(String.format(format, MIN_PERSONS)); valid = false; } return valid; } private void save() { String title = getCalculationTitle(); Currency currency = (Currency) currencyField.getSelectedItem(); List<String> personNames = getPersonNames(); DataBaseHelper dbHelper = new DataBaseHelper(this); CalculationDataSource dataSource = new CalculationDataSource(dbHelper); Calculation calculation = dataSource.createCalculation(title, currency.getCurrencyCode(), personNames); dbHelper.close(); Intent intent = new Intent(this, ExpenseListActivity.class); intent.putExtra(ExpenseListActivity.PARAM_CALCULATION_ID, calculation.getId()); startActivity(intent); finish(); } private void doSave() { try { if (validate()) save(); } catch (Exception e) { Toast.makeText(this, "Error saving calculation", Toast.LENGTH_LONG).show(); Log.e(CalculationEditorActivity.class.toString(), "Error saving calculation", e); } } }