Java tutorial
/* This file is part of My Expenses. * My Expenses is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * My Expenses is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with My Expenses. If not, see <http://www.gnu.org/licenses/>. */ package org.totschnig.myexpenses.fragment; import static org.totschnig.myexpenses.provider.DatabaseConstants.*; import org.totschnig.myexpenses.R; import org.totschnig.myexpenses.activity.ExpenseEdit; import org.totschnig.myexpenses.activity.MyExpenses; import org.totschnig.myexpenses.activity.ProtectedFragmentActivity; import org.totschnig.myexpenses.adapter.SplitPartAdapter; import org.totschnig.myexpenses.model.Account; import org.totschnig.myexpenses.model.Money; import org.totschnig.myexpenses.provider.TransactionProvider; import org.totschnig.myexpenses.task.TaskExecutionFragment; import org.totschnig.myexpenses.util.Utils; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ContextMenu.ContextMenuInfo; import android.widget.AdapterView; import android.widget.ListView; import android.widget.TextView; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.OnItemClickListener; import icepick.Icepick; import icepick.State; //TODO: consider moving to ListFragment public class SplitPartList extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { // SplitPartAdapter mAdapter; private TextView balanceTv; private long transactionSum = 0; private Money unsplitAmount; private FloatingActionButton fab; @State long parentId; @State long accountId; public static SplitPartList newInstance(Long parentId, Long accountId) { SplitPartList f = new SplitPartList(); Bundle bundle = new Bundle(); bundle.putLong(KEY_PARENTID, parentId); bundle.putLong(KEY_ACCOUNTID, accountId); f.setArguments(bundle); return f; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); setRetainInstance(true); if (savedInstanceState == null) { parentId = getArguments().getLong(KEY_PARENTID); accountId = getArguments().getLong(KEY_ACCOUNTID); } else { Icepick.restoreInstanceState(this, savedInstanceState); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Icepick.saveInstanceState(this, outState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final FragmentActivity ctx = getActivity(); View v = inflater.inflate(R.layout.split_parts_list, container, false); View emptyView = v.findViewById(R.id.empty); balanceTv = (TextView) v.findViewById(R.id.end); ListView lv = (ListView) v.findViewById(R.id.list); // Create an array to specify the fields we want to display in the list String[] from = new String[] { KEY_LABEL_MAIN, KEY_AMOUNT }; // and an array of the fields we want to bind those fields to int[] to = new int[] { R.id.category, R.id.amount }; requireLoaders(); // Now create a simple cursor adapter and set it to display final Account account = Account.getInstanceFromDb(accountId); mAdapter = new SplitPartAdapter(ctx, R.layout.split_part_row, null, from, to, 0, account.currency); lv.setAdapter(mAdapter); lv.setEmptyView(emptyView); lv.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> a, View v, int position, long id) { Intent i = new Intent(ctx, ExpenseEdit.class); i.putExtra(KEY_ROWID, id); //i.putExtra("operationType", operationType); startActivityForResult(i, MyExpenses.EDIT_TRANSACTION_REQUEST); } }); registerForContextMenu(lv); fab = ((FloatingActionButton) v.findViewById(R.id.CREATE_COMMAND)); fab.setContentDescription(Utils.concatResStrings(getActivity(), ". ", R.string.menu_create_split_part_category, R.string.menu_create_split_part_transfer)); updateFabColor(account.color); return v; } public void updateFabColor(int color) { Utils.setBackgroundTintListOnFab(fab, color); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); menu.add(0, R.id.DELETE_COMMAND, 0, R.string.menu_delete); } @Override public boolean onContextItemSelected(android.view.MenuItem item) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); switch (item.getItemId()) { case R.id.DELETE_COMMAND: ((ProtectedFragmentActivity) getActivity()).startTaskExecution( TaskExecutionFragment.TASK_DELETE_TRANSACTION, new Long[] { info.id }, Boolean.valueOf(false), 0); return true; } return super.onContextItemSelected(item); } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { String[] selectionArgs = new String[] { String.valueOf(parentId) }; CursorLoader cursorLoader = null; Uri uri = TransactionProvider.UNCOMMITTED_URI; switch (id) { case ExpenseEdit.TRANSACTION_CURSOR: cursorLoader = new CursorLoader(getActivity(), uri, null, "parent_id = ?", selectionArgs, null); return cursorLoader; case ExpenseEdit.SUM_CURSOR: cursorLoader = new CursorLoader(getActivity(), uri, new String[] { "sum(" + KEY_AMOUNT + ")" }, "parent_id = ?", selectionArgs, null); } return cursorLoader; } @Override public void onLoadFinished(Loader<Cursor> arg0, Cursor c) { switch (arg0.getId()) { case ExpenseEdit.TRANSACTION_CURSOR: mAdapter.swapCursor(c); break; case ExpenseEdit.SUM_CURSOR: c.moveToFirst(); transactionSum = c.getLong(0); updateBalance(); } } @Override public void onLoaderReset(Loader<Cursor> arg0) { switch (arg0.getId()) { case ExpenseEdit.TRANSACTION_CURSOR: mAdapter.swapCursor(null); break; } } public void updateBalance() { ExpenseEdit ctx = (ExpenseEdit) getActivity(); if (ctx == null) return; unsplitAmount = ctx.getAmount(); //when we are called before transaction is loaded in parent activity if (unsplitAmount == null) return; unsplitAmount.setAmountMinor(unsplitAmount.getAmountMinor() - transactionSum); if (balanceTv != null) balanceTv.setText(Utils.formatCurrency(unsplitAmount)); } public boolean splitComplete() { return unsplitAmount != null && unsplitAmount.getAmountMinor() == 0L; } public int getSplitCount() { return mAdapter.getCount(); } public void updateAccount(Account account) { accountId = account.getId(); mAdapter.setCurrency(account.currency); mAdapter.notifyDataSetChanged(); updateBalance(); updateFabColor(account.color); } public void updateParent(long parentId) { this.parentId = parentId; requireLoaders(); } private void requireLoaders() { Utils.requireLoader(getActivity().getSupportLoaderManager(), ExpenseEdit.TRANSACTION_CURSOR, null, this); Utils.requireLoader(getActivity().getSupportLoaderManager(), ExpenseEdit.SUM_CURSOR, null, this); } }