/*
* Copyright (c) 2015 Ngewi Fet <ngewif@gmail.com>
*
* 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 org.gnucash.android.ui.budget;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.inputmethodservice.KeyboardView;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import org.gnucash.android.R;
import org.gnucash.android.db.DatabaseSchema;
import org.gnucash.android.db.adapter.AccountsDbAdapter;
import org.gnucash.android.model.BudgetAmount;
import org.gnucash.android.model.Commodity;
import org.gnucash.android.model.Money;
import org.gnucash.android.ui.common.UxArgument;
import org.gnucash.android.ui.util.widget.CalculatorEditText;
import org.gnucash.android.util.QualifiedAccountNameCursorAdapter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
/**
* Fragment for editing budgeting amounts
*/
public class BudgetAmountEditorFragment extends Fragment {
private Cursor mAccountCursor;
private QualifiedAccountNameCursorAdapter mAccountCursorAdapter;
private List<View> mBudgetAmountViews = new ArrayList<>();
private AccountsDbAdapter mAccountsDbAdapter;
@BindView(R.id.budget_amount_layout) LinearLayout mBudgetAmountTableLayout;
@BindView(R.id.calculator_keyboard) KeyboardView mKeyboardView;
public static BudgetAmountEditorFragment newInstance(Bundle args){
BudgetAmountEditorFragment fragment = new BudgetAmountEditorFragment();
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_budget_amount_editor, container, false);
ButterKnife.bind(this, view);
setupAccountSpinnerAdapter();
return view;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAccountsDbAdapter = AccountsDbAdapter.getInstance();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ActionBar actionBar = ((AppCompatActivity)getActivity()).getSupportActionBar();
assert actionBar != null;
actionBar.setTitle("Edit Budget Amounts");
setHasOptionsMenu(true);
ArrayList<BudgetAmount> budgetAmounts = getArguments().getParcelableArrayList(UxArgument.BUDGET_AMOUNT_LIST);
if (budgetAmounts != null) {
if (budgetAmounts.isEmpty()){
BudgetAmountViewHolder viewHolder = (BudgetAmountViewHolder) addBudgetAmountView(null).getTag();
viewHolder.removeItemBtn.setVisibility(View.GONE); //there should always be at least one
} else {
loadBudgetAmountViews(budgetAmounts);
}
} else {
BudgetAmountViewHolder viewHolder = (BudgetAmountViewHolder) addBudgetAmountView(null).getTag();
viewHolder.removeItemBtn.setVisibility(View.GONE); //there should always be at least one
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.budget_amount_editor_actions, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.menu_add_budget_amount:
addBudgetAmountView(null);
return true;
case R.id.menu_save:
saveBudgetAmounts();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**
* Checks if the budget amounts can be saved
* @return {@code true} if all amounts a properly entered, {@code false} otherwise
*/
private boolean canSave(){
for (View budgetAmountView : mBudgetAmountViews) {
BudgetAmountViewHolder viewHolder = (BudgetAmountViewHolder) budgetAmountView.getTag();
viewHolder.amountEditText.evaluate();
if (viewHolder.amountEditText.getError() != null){
return false;
}
//at least one account should be loaded (don't create budget with empty account tree
if (viewHolder.budgetAccountSpinner.getCount() == 0){
Toast.makeText(getActivity(), "You need an account hierarchy to create a budget!",
Toast.LENGTH_SHORT).show();
return false;
}
}
return true;
}
private void saveBudgetAmounts() {
if (canSave()){
ArrayList<BudgetAmount> budgetAmounts = (ArrayList<BudgetAmount>) extractBudgetAmounts();
Intent data = new Intent();
data.putParcelableArrayListExtra(UxArgument.BUDGET_AMOUNT_LIST, budgetAmounts);
getActivity().setResult(Activity.RESULT_OK, data);
getActivity().finish();
}
}
/**
* Load views for the budget amounts
* @param budgetAmounts List of {@link BudgetAmount}s
*/
private void loadBudgetAmountViews(List<BudgetAmount> budgetAmounts){
for (BudgetAmount budgetAmount : budgetAmounts) {
addBudgetAmountView(budgetAmount);
}
}
/**
* Inflates a new BudgetAmount item view and adds it to the UI.
* <p>If the {@code budgetAmount} is not null, then it is used to initialize the view</p>
* @param budgetAmount Budget amount
*/
private View addBudgetAmountView(BudgetAmount budgetAmount){
LayoutInflater layoutInflater = getActivity().getLayoutInflater();
View budgetAmountView = layoutInflater.inflate(R.layout.item_budget_amount,
mBudgetAmountTableLayout, false);
BudgetAmountViewHolder viewHolder = new BudgetAmountViewHolder(budgetAmountView);
if (budgetAmount != null){
viewHolder.bindViews(budgetAmount);
}
mBudgetAmountTableLayout.addView(budgetAmountView, 0);
mBudgetAmountViews.add(budgetAmountView);
// mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
return budgetAmountView;
}
/**
* Loads the accounts in the spinner
*/
private void setupAccountSpinnerAdapter(){
String conditions = "(" + DatabaseSchema.AccountEntry.COLUMN_HIDDEN + " = 0 )";
if (mAccountCursor != null) {
mAccountCursor.close();
}
mAccountCursor = mAccountsDbAdapter.fetchAccountsOrderedByFavoriteAndFullName(conditions, null);
mAccountCursorAdapter = new QualifiedAccountNameCursorAdapter(getActivity(), mAccountCursor);
}
/**
* Extract {@link BudgetAmount}s from the views
* @return List of budget amounts
*/
private List<BudgetAmount> extractBudgetAmounts(){
List<BudgetAmount> budgetAmounts = new ArrayList<>();
for (View view : mBudgetAmountViews) {
BudgetAmountViewHolder viewHolder = (BudgetAmountViewHolder) view.getTag();
BigDecimal amountValue = viewHolder.amountEditText.getValue();
if (amountValue == null)
continue;
Money amount = new Money(amountValue, Commodity.DEFAULT_COMMODITY);
String accountUID = mAccountsDbAdapter.getUID(viewHolder.budgetAccountSpinner.getSelectedItemId());
BudgetAmount budgetAmount = new BudgetAmount(amount, accountUID);
budgetAmounts.add(budgetAmount);
}
return budgetAmounts;
}
/**
* View holder for budget amounts
*/
class BudgetAmountViewHolder{
@BindView(R.id.currency_symbol) TextView currencySymbolTextView;
@BindView(R.id.input_budget_amount) CalculatorEditText amountEditText;
@BindView(R.id.btn_remove_item) ImageView removeItemBtn;
@BindView(R.id.input_budget_account_spinner) Spinner budgetAccountSpinner;
View itemView;
public BudgetAmountViewHolder(View view){
itemView = view;
ButterKnife.bind(this, view);
itemView.setTag(this);
amountEditText.bindListeners(mKeyboardView);
budgetAccountSpinner.setAdapter(mAccountCursorAdapter);
budgetAccountSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String currencyCode = mAccountsDbAdapter.getCurrencyCode(mAccountsDbAdapter.getUID(id));
Commodity commodity = Commodity.getInstance(currencyCode);
currencySymbolTextView.setText(commodity.getSymbol());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
//nothing to see here, move along
}
});
removeItemBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mBudgetAmountTableLayout.removeView(itemView);
mBudgetAmountViews.remove(itemView);
}
});
}
public void bindViews(BudgetAmount budgetAmount){
amountEditText.setValue(budgetAmount.getAmount().asBigDecimal());
budgetAccountSpinner.setSelection(mAccountCursorAdapter.getPosition(budgetAmount.getAccountUID()));
}
}
}