package co.smartreceipts.android.settings.widget; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.app.ActionBar; import android.support.v7.widget.Toolbar; 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.ArrayAdapter; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.Spinner; import android.widget.TextView; import java.util.List; import co.smartreceipts.android.R; import co.smartreceipts.android.fragments.WBFragment; import co.smartreceipts.android.model.Column; import co.smartreceipts.android.model.Receipt; import co.smartreceipts.android.model.impl.columns.receipts.ReceiptColumnDefinitions; import co.smartreceipts.android.persistence.database.controllers.TableEventsListener; import co.smartreceipts.android.persistence.database.controllers.impl.ColumnTableController; import co.smartreceipts.android.persistence.database.operations.DatabaseOperationMetadata; import co.smartreceipts.android.widget.UserSelectionTrackingOnItemSelectedListener; public abstract class ColumnsListFragment extends WBFragment implements TableEventsListener<Column<Receipt>> { public static String TAG = "ColumnsListFragment"; private final AdapterView.OnItemSelectedListener mSpinnerSelectionListener = new ColumnTypeChangeSelectionListener(); private BaseAdapter mAdapter; private Toolbar mToolbar; private ListView mListView; private ColumnTableController mColumnTableController; private List<Column<Receipt>> mColumns; private ArrayAdapter<Column<Receipt>> mSpinnerAdapter; private boolean mDisableInsertsAndDeletes = false; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mColumnTableController = getColumnTableController(); mAdapter = getAdapter(); mSpinnerAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_item, getReceiptColumnDefinitions().getAllColumns()); mSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); setHasOptionsMenu(true); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.simple_list, container, false); mToolbar = (Toolbar) rootView.findViewById(R.id.toolbar); mListView = (ListView) rootView.findViewById(android.R.id.list); return rootView; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setSupportActionBar(mToolbar); } @Override public void onResume() { super.onResume(); final ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setSubtitle(null); } mColumnTableController.subscribe(this); mColumnTableController.get(); } protected abstract ReceiptColumnDefinitions getReceiptColumnDefinitions(); protected abstract ColumnTableController getColumnTableController(); @Override public void onPause() { mColumnTableController.unsubscribe(this); super.onPause(); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu_settings_columns, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { getActivity().onBackPressed(); return true; } if (mDisableInsertsAndDeletes) { // Temporarily until we receive a callback below return false; } if (item.getItemId() == R.id.menu_settings_add) { mDisableInsertsAndDeletes = true; mColumnTableController.insertDefaultColumn(); return true; } else if (item.getItemId() == R.id.menu_settings_delete) { mDisableInsertsAndDeletes = true; mColumnTableController.deleteLast(new DatabaseOperationMetadata()); return true; } else { return super.onOptionsItemSelected(item); } } @Override public void onGetSuccess(@NonNull List<Column<Receipt>> list) { if (isResumed()) { mColumns = list; if (mListView.getAdapter() == null) { mListView.setAdapter(mAdapter); } else { mAdapter.notifyDataSetChanged(); } } } @Override public void onGetFailure(@Nullable Throwable e) { // No-op } @Override public void onInsertSuccess(@NonNull Column<Receipt> column, @NonNull DatabaseOperationMetadata databaseOperationMetadata) { mDisableInsertsAndDeletes = false; if (isResumed()) { mColumnTableController.get(); } } @Override public void onInsertFailure(@NonNull Column<Receipt> column, @Nullable Throwable e, @NonNull DatabaseOperationMetadata databaseOperationMetadata) { mDisableInsertsAndDeletes = false; } @Override public void onUpdateSuccess(@NonNull Column<Receipt> oldT, @NonNull Column<Receipt> newT, @NonNull DatabaseOperationMetadata databaseOperationMetadata) { if (isResumed()) { mColumnTableController.get(); } } @Override public void onUpdateFailure(@NonNull Column<Receipt> oldT, @Nullable Throwable e, @NonNull DatabaseOperationMetadata databaseOperationMetadata) { // No-op } @Override public void onDeleteSuccess(@NonNull Column<Receipt> column, @NonNull DatabaseOperationMetadata databaseOperationMetadata) { mDisableInsertsAndDeletes = false; if (isResumed()) { mColumnTableController.get(); } } @Override public void onDeleteFailure(@NonNull Column<Receipt> column, @Nullable Throwable e, @NonNull DatabaseOperationMetadata databaseOperationMetadata) { mDisableInsertsAndDeletes = false; } protected BaseAdapter getAdapter() { return new SettingsListAdapter(LayoutInflater.from(getActivity())); } protected int getListItemLayoutId() { return R.layout.settings_column_card_item; } private static final class SpinnerTag { public Column<Receipt> column; } private static final class MyViewHolder { public TextView column; public Spinner spinner; } private class SettingsListAdapter extends BaseAdapter { private final LayoutInflater mInflater; public SettingsListAdapter(LayoutInflater inflater) { mInflater = inflater; } @Override public int getCount() { return mColumns.size(); } @Override public Column<Receipt> getItem(int i) { return mColumns.get(i); } @Override public long getItemId(int i) { return i; } @Override public View getView(int i, View convertView, ViewGroup parent) { MyViewHolder holder; if (convertView == null) { convertView = mInflater.inflate(getListItemLayoutId(), parent, false); holder = new MyViewHolder(); holder.column = (TextView) convertView.findViewById(android.R.id.title); holder.spinner = (Spinner) convertView.findViewById(R.id.column_spinner); holder.spinner.setAdapter(mSpinnerAdapter); holder.spinner.setTag(new SpinnerTag()); convertView.setTag(holder); } else { holder = (MyViewHolder) convertView.getTag(); holder.spinner.setOnItemSelectedListener(null); // Null out each time to not artificially hit the setter } holder.column.setText(getString(R.string.column_item, Integer.toString(i+1))); //Add +1 to make it not 0-th index final int selectedPosition = getColumnPositionByName(i); if (selectedPosition >= 0) { holder.spinner.setSelection(selectedPosition); } holder.spinner.setOnItemSelectedListener(mSpinnerSelectionListener); SpinnerTag spinnerTag = (SpinnerTag) holder.spinner.getTag(); spinnerTag.column = getItem(i); return convertView; } /** * Attempts to get the position in the spinner based on the column name. Since column "equals" * also takes into account the actual position in the database, we do a pseudo equals here by * name * @param columnPosition the position of the column * @return the position in the spinner or -1 if unknown */ private int getColumnPositionByName(int columnPosition) { final String columnName = getItem(columnPosition).getName(); for (int i = 0; i < mSpinnerAdapter.getCount(); i++) { if (columnName.equals(mSpinnerAdapter.getItem(i).getName())) { return i; } } return -1; } } private class ColumnTypeChangeSelectionListener extends UserSelectionTrackingOnItemSelectedListener { @Override public void onUserSelectedNewItem(AdapterView<?> parent, View view, int position, long id, int previousPosition) { final SpinnerTag spinnerTag = (SpinnerTag) parent.getTag(); final Column<Receipt> oldColumn = spinnerTag.column; final Column<Receipt> newColumn = mSpinnerAdapter.getItem(position); mColumnTableController.update(oldColumn, newColumn, new DatabaseOperationMetadata()); } @Override public void onNothingSelected(AdapterView<?> adapterView) { } } }