org.gnucash.android.ui.budget.BudgetAmountEditorFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.gnucash.android.ui.budget.BudgetAmountEditorFragment.java

Source

/*
 * 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.Currency;
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));
                    Currency currency = Currency.getInstance(currencyCode);
                    currencySymbolTextView.setText(currency.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()));
        }
    }
}