Java tutorial
/* * 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.content.res.Configuration; import android.graphics.Color; 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.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; 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.ProgressBar; import android.widget.TextView; import com.github.mikephil.charting.charts.BarChart; import com.github.mikephil.charting.components.LimitLine; import com.github.mikephil.charting.data.BarData; import com.github.mikephil.charting.data.BarDataSet; import com.github.mikephil.charting.data.BarEntry; import org.gnucash.android.R; import org.gnucash.android.db.DatabaseSchema; import org.gnucash.android.db.adapter.AccountsDbAdapter; import org.gnucash.android.db.adapter.BudgetsDbAdapter; import org.gnucash.android.model.Budget; import org.gnucash.android.model.BudgetAmount; import org.gnucash.android.model.Money; import org.gnucash.android.ui.common.FormActivity; import org.gnucash.android.ui.common.Refreshable; import org.gnucash.android.ui.common.UxArgument; import org.gnucash.android.ui.transaction.TransactionsActivity; import org.gnucash.android.ui.util.widget.EmptyRecyclerView; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; /** * Fragment for displaying budget details */ public class BudgetDetailFragment extends Fragment implements Refreshable { @BindView(R.id.primary_text) TextView mBudgetNameTextView; @BindView(R.id.secondary_text) TextView mBudgetDescriptionTextView; @BindView(R.id.budget_recurrence) TextView mBudgetRecurrence; @BindView(R.id.budget_amount_recycler) EmptyRecyclerView mRecyclerView; private String mBudgetUID; private BudgetsDbAdapter mBudgetsDbAdapter; public static BudgetDetailFragment newInstance(String budgetUID) { BudgetDetailFragment fragment = new BudgetDetailFragment(); Bundle args = new Bundle(); args.putString(UxArgument.BUDGET_UID, budgetUID); fragment.setArguments(args); return fragment; } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_budget_detail, container, false); ButterKnife.bind(this, view); mBudgetDescriptionTextView.setMaxLines(3); mRecyclerView.setHasFixedSize(true); if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 2); mRecyclerView.setLayoutManager(gridLayoutManager); } else { LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity()); mRecyclerView.setLayoutManager(mLayoutManager); } return view; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mBudgetsDbAdapter = BudgetsDbAdapter.getInstance(); mBudgetUID = getArguments().getString(UxArgument.BUDGET_UID); bindViews(); setHasOptionsMenu(true); } private void bindViews() { Budget budget = mBudgetsDbAdapter.getRecord(mBudgetUID); mBudgetNameTextView.setText(budget.getName()); String description = budget.getDescription(); if (description != null && !description.isEmpty()) mBudgetDescriptionTextView.setText(description); else { mBudgetDescriptionTextView.setVisibility(View.GONE); } mBudgetRecurrence.setText(budget.getRecurrence().getRepeatString()); mRecyclerView.setAdapter(new BudgetAmountAdapter()); } @Override public void onResume() { super.onResume(); refresh(); View view = getActivity().findViewById(R.id.fab_create_budget); if (view != null) { view.setVisibility(View.GONE); } } @Override public void refresh() { bindViews(); String budgetName = mBudgetsDbAdapter.getAttribute(mBudgetUID, DatabaseSchema.BudgetEntry.COLUMN_NAME); ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar(); assert actionBar != null; actionBar.setTitle("Budget: " + budgetName); } @Override public void refresh(String budgetUID) { mBudgetUID = budgetUID; refresh(); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.budget_actions, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_edit_budget: Intent addAccountIntent = new Intent(getActivity(), FormActivity.class); addAccountIntent.setAction(Intent.ACTION_INSERT_OR_EDIT); addAccountIntent.putExtra(UxArgument.FORM_TYPE, FormActivity.FormType.BUDGET.name()); addAccountIntent.putExtra(UxArgument.BUDGET_UID, mBudgetUID); startActivityForResult(addAccountIntent, 0x11); return true; default: return false; } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK) { refresh(); } } public class BudgetAmountAdapter extends RecyclerView.Adapter<BudgetAmountAdapter.BudgetAmountViewHolder> { private List<BudgetAmount> mBudgetAmounts; private Budget mBudget; public BudgetAmountAdapter() { mBudget = mBudgetsDbAdapter.getRecord(mBudgetUID); mBudgetAmounts = mBudget.getCompactedBudgetAmounts(); } @Override public BudgetAmountViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(getActivity()).inflate(R.layout.cardview_budget_amount, parent, false); return new BudgetAmountViewHolder(view); } @Override public void onBindViewHolder(BudgetAmountViewHolder holder, final int position) { BudgetAmount budgetAmount = mBudgetAmounts.get(position); Money projectedAmount = budgetAmount.getAmount(); AccountsDbAdapter accountsDbAdapter = AccountsDbAdapter.getInstance(); holder.budgetAccount.setText(accountsDbAdapter.getAccountFullName(budgetAmount.getAccountUID())); holder.budgetAmount.setText(projectedAmount.formattedString()); Money spentAmount = accountsDbAdapter.getAccountBalance(budgetAmount.getAccountUID(), mBudget.getStartofCurrentPeriod(), mBudget.getEndOfCurrentPeriod()); holder.budgetSpent.setText(spentAmount.abs().formattedString()); holder.budgetLeft.setText(projectedAmount.subtract(spentAmount.abs()).formattedString()); double budgetProgress = 0; if (projectedAmount.asDouble() != 0) { budgetProgress = spentAmount.asBigDecimal() .divide(projectedAmount.asBigDecimal(), spentAmount.getCommodity().getSmallestFractionDigits(), RoundingMode.HALF_EVEN) .doubleValue(); } holder.budgetIndicator.setProgress((int) (budgetProgress * 100)); holder.budgetSpent.setTextColor(BudgetsActivity.getBudgetProgressColor(1 - budgetProgress)); holder.budgetLeft.setTextColor(BudgetsActivity.getBudgetProgressColor(1 - budgetProgress)); generateChartData(holder.budgetChart, budgetAmount); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(getActivity(), TransactionsActivity.class); intent.putExtra(UxArgument.SELECTED_ACCOUNT_UID, mBudgetAmounts.get(position).getAccountUID()); startActivityForResult(intent, 0x10); } }); } /** * Generate the chart data for the chart * @param barChart View where to display the chart * @param budgetAmount BudgetAmount to visualize */ public void generateChartData(BarChart barChart, BudgetAmount budgetAmount) { // FIXME: 25.10.15 chart is broken AccountsDbAdapter accountsDbAdapter = AccountsDbAdapter.getInstance(); List<BarEntry> barEntries = new ArrayList<>(); List<String> xVals = new ArrayList<>(); //todo: refactor getNumberOfPeriods into budget int budgetPeriods = (int) mBudget.getNumberOfPeriods(); budgetPeriods = budgetPeriods == 0 ? 12 : budgetPeriods; int periods = mBudget.getRecurrence().getNumberOfPeriods(budgetPeriods); //// FIXME: 15.08.2016 why do we need number of periods for (int periodNum = 1; periodNum <= periods; periodNum++) { BigDecimal amount = accountsDbAdapter.getAccountBalance(budgetAmount.getAccountUID(), mBudget.getStartOfPeriod(periodNum), mBudget.getEndOfPeriod(periodNum)).asBigDecimal(); if (amount.equals(BigDecimal.ZERO)) continue; barEntries.add(new BarEntry(amount.floatValue(), periodNum)); xVals.add(mBudget.getRecurrence().getTextOfCurrentPeriod(periodNum)); } String label = accountsDbAdapter.getAccountName(budgetAmount.getAccountUID()); BarDataSet barDataSet = new BarDataSet(barEntries, label); BarData barData = new BarData(xVals, barDataSet); LimitLine limitLine = new LimitLine(budgetAmount.getAmount().asBigDecimal().floatValue()); limitLine.setLineWidth(2f); limitLine.setLineColor(Color.RED); barChart.setData(barData); barChart.getAxisLeft().addLimitLine(limitLine); BigDecimal maxValue = budgetAmount.getAmount() .add(budgetAmount.getAmount().multiply(new BigDecimal("0.2"))).asBigDecimal(); barChart.getAxisLeft().setAxisMaxValue(maxValue.floatValue()); barChart.animateX(1000); barChart.setAutoScaleMinMaxEnabled(true); barChart.setDrawValueAboveBar(true); barChart.invalidate(); } @Override public int getItemCount() { return mBudgetAmounts.size(); } class BudgetAmountViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.budget_account) TextView budgetAccount; @BindView(R.id.budget_amount) TextView budgetAmount; @BindView(R.id.budget_spent) TextView budgetSpent; @BindView(R.id.budget_left) TextView budgetLeft; @BindView(R.id.budget_indicator) ProgressBar budgetIndicator; @BindView(R.id.budget_chart) BarChart budgetChart; public BudgetAmountViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } } }