Back to project page Books.
The source code is released under:
Apache License
If you think the Android project Books listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package com.contender.books; /*w ww . j a va 2s . c o m*/ import java.util.Calendar; import java.util.Date; import org.joda.time.DateTime; import org.joda.time.Days; import android.app.Activity; import android.app.AlertDialog; import android.app.DialogFragment; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.provider.CalendarContract.Events; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.google.zxing.integration.android.IntentIntegrator; import com.google.zxing.integration.android.IntentResult; /** * Implements a ListView that connects to the {@link BooksStorage#BOOKS_TABLE_NAME} * table and displays it. * <p> * Implements DialogListeners and onActivityResult to catch results from * user interaction and launch the appropriate activity/intent. * * @author Paul Klinkenberg <pklinken@gmail.com> * @version {@value #BOOKS_VERSION} */ public class MainView extends Activity implements AdapterView.OnItemClickListener, EditOrDeleteDialogFragment.EditOrDeleteDialogListener, ScanOrManualDialogFragment.ScanOrManualDialogListener { // FIXME: Layout bug where, after scanning a barcode and immediately pressing Back, the layout becomes full screen // with the status bar obscuring half the actionbar. // These constants identify the different Intents and data one can send to BookActivity public static final String EXTRA_INDEX = "EditBookIndex"; public static final String EXTRA_ISBN = "EditBookISBN"; public static final String ACTION_ADD_ISBN = "AddBookIsbn"; public static final String ACTION_ADD_MANUAL = "AddBookManual"; public static final String ACTION_EDIT = "EditBook"; // These contants define the SharedPreferences location and keys. public static final String PREFS_NAME = "BooksPreferences"; public static final String PREFS_PERIOD_LENGTH = "BooksPeriodLength"; public static final String PREFS_PERIOD_UNIT = "BooksPeriodUnit"; public static final String PREFS_SORT_ORDER = "BooksSortOrder"; public static final String BOOKS_VERSION = "0.4"; private static final String TAG = "MainView"; /** * {@link onItemClick} sets this to the {@link BookStorage#COLUMN_NAME__ID} of * the clicked row in our ListView. */ private static int selectionIndex = -1; private ListView listView; public static BooksStorage BooksProvider; private Cursor mCursor; BaseAdapter adapter; /** * Text converter implemented by the ListView * <p> * if the processed field is {@link R.id.itemDuedateText} returns a string * to display time remaining in days/weeks/months or that the book is late. */ private String convText(TextView v, String text) { if(v.getId() == R.id.itemDuedateText) { Date dueDate = new Date(Long.parseLong(text)); Date today = new Date(); Resources res = getResources(); int days = Days.daysBetween(new DateTime(today), new DateTime(dueDate)).getDays(); String remTime = new String(); if(days == 0) { remTime = res.getString(R.string.conv_text_today); return remTime; } if(days < 0) { remTime = res.getQuantityString(R.plurals.plural_days_overdue, Math.abs(days), Math.abs(days)); return remTime; } int x = days / 365; if(x > 0) { remTime = "+" + x + " " + res.getQuantityString(R.plurals.plural_years, x); return remTime; } x = days / 30; if(x > 0) { remTime = "+" + x + " " + res.getQuantityString(R.plurals.plural_months, x); return remTime; } x = days / 7; if(x > 0) { remTime = "+" + x + " " + res.getQuantityString(R.plurals.plural_weeks, x); return remTime; } if(days > 0) { remTime = days + " " + res.getQuantityString(R.plurals.plural_days, days); return remTime; } return remTime; } return text; } /** * Reloads the {@link BookStorage.#BOOKS_TABLE_NAME} table and displays it in our * ListView. * <p> * Also uses SharedPreferences to determine sorting order. */ private void refreshOverview() { SharedPreferences settings = this.getSharedPreferences(MainView.PREFS_NAME, 0); int sortOrder = settings.getInt(PREFS_SORT_ORDER, 0); String sortOrderString; switch (sortOrder) { case 0: sortOrderString = new String(BooksStorage.COLUMN_NAME_DUEDATE); break; case 1: sortOrderString = new String(BooksStorage.COLUMN_NAME_BOOK); break; case 2: sortOrderString = new String(BooksStorage.COLUMN_NAME_CONTACT); break; default: sortOrderString = null; } mCursor = BooksProvider.query(BooksStorage.BOOKS_TABLE_NAME, new String[] { BooksStorage.COLUMN_NAME__ID, BooksStorage.COLUMN_NAME_BOOK, BooksStorage.COLUMN_NAME_CONTACT, BooksStorage.COLUMN_NAME_DUEDATE }, null, null, sortOrderString); if(mCursor == null) { Log.e(TAG, "Received empty cursor"); finish(); } adapter = new SpecialCursorAdapter(this, R.layout.overview_item, mCursor, new String[] { BooksStorage.COLUMN_NAME_BOOK, BooksStorage.COLUMN_NAME_CONTACT, BooksStorage.COLUMN_NAME_DUEDATE }, new int[] { R.id.itemBookText, R.id.itemContactText, R.id.itemDuedateText }, 0) { @Override public void setViewText(TextView v, String text) { super.setViewText(v, convText(v, text));; } }; listView.setAdapter(adapter); } /** * Launches {@link BookActivity} with the ACTION_EDIT intent and {@link selectionIndex} * <p> * Implements {@link EditOrDeleteDialogFragment.EditOrDeleteDialogListener} */ @Override public void onDialogEditClick(DialogFragment dialog) { // Edit button Intent intent = new Intent(); intent.setClass(getApplicationContext(), BookActivity.class); intent.setAction(ACTION_EDIT); intent.putExtra(EXTRA_INDEX, selectionIndex); startActivity(intent); } /** Deletes calendar event associated with the db row where _id IS {@link row}. * * @param row the _id of the db entry whose calendar event is to be deleted. */ private void deleteCalendarEvent(int row) { int column; long eventID; Cursor cursor = MainView.BooksProvider.query(BooksStorage.BOOKS_TABLE_NAME, new String[] { BooksStorage.COLUMN_NAME_CALENDAREVENTID }, BooksStorage.COLUMN_NAME__ID + " IS ?", new String[] { new String(Integer.toString(row)) }, null); if(!cursor.moveToFirst()) { // Something went wrong Log.e(TAG, "Received empty cursor."); return; } column = cursor.getColumnIndex(BooksStorage.COLUMN_NAME_CALENDAREVENTID); eventID = cursor.getLong(column); ContentResolver cr = getContentResolver(); Uri deleteUri = null; deleteUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); int rows = cr.delete(deleteUri, null, null); Log.d(TAG, "Rows deleted: " + rows); } /** * Deletes the row from the DB whose _id IS {@link selectionIndex} * <p> * If the row has a calendarevent it will also call {@link deleteCalendarEvent} * <p> * Implements {@link EditOrDeleteDialogFragment.EditOrDeleteDialogListener} * * @param dialog dialog dialog that called this function */ @Override public void onDialogDeleteClick(DialogFragment dialog) { // Delete button Cursor cursor = BooksProvider.query(BooksStorage.BOOKS_TABLE_NAME, new String[] { BooksStorage.COLUMN_NAME_BOOK, BooksStorage.COLUMN_NAME_AUTHOR, BooksStorage.COLUMN_NAME_CONTACT, BooksStorage.COLUMN_NAME_DUEDATE, BooksStorage.COLUMN_NAME_LOANDATE, BooksStorage.COLUMN_NAME_HASREMINDER }, BooksStorage.COLUMN_NAME__ID + " IS ?", new String[] { new String(Integer.toString(selectionIndex)) }, null); if(!cursor.moveToFirst()) { // Something went wrong Log.e(TAG, "Received empty cursor."); return; } ContentValues values = new ContentValues(); values.put(BooksStorage.COLUMN_NAME_BOOK, cursor.getString(cursor.getColumnIndex(BooksStorage.COLUMN_NAME_BOOK))); values.put(BooksStorage.COLUMN_NAME_AUTHOR, cursor.getString(cursor.getColumnIndex(BooksStorage.COLUMN_NAME_AUTHOR))); values.put(BooksStorage.COLUMN_NAME_CONTACT, cursor.getString(cursor.getColumnIndex(BooksStorage.COLUMN_NAME_CONTACT))); Calendar rightNow = Calendar.getInstance(); values.put(BooksStorage.COLUMN_NAME_RETURNDATE, rightNow.getTimeInMillis()); if(BooksProvider.insert(BooksStorage.HISTORY_TABLE_NAME, values) < 0) { Log.w(TAG, "Error inserting in history table."); return; } int column = cursor.getColumnIndex(BooksStorage.COLUMN_NAME_HASREMINDER); if(cursor.getInt(column) != 0) { // cursor has no getBool() method so we will assume any non-zero value is TRUE deleteCalendarEvent(selectionIndex); } if(BooksProvider.delete(BooksStorage.BOOKS_TABLE_NAME, BooksStorage.COLUMN_NAME__ID + "=" + selectionIndex, null ) < 0) { Log.e(TAG, "Error deleting from books table."); return; } refreshOverview(); } /** * Starts the scan book intent to obtain an ISBN number. * <p> * Implements {@link ScanOrManualDialogFragment.ScanOrManualDialogListener} * * @param dialog dialog dialog that called this function */ @Override public void onDialogScanClick(DialogFragment dialog) { // Start scanner intent, catch result in this activity and launch addbook activity with ISBN data IntentIntegrator integrator = new IntentIntegrator(this); integrator.initiateScan(); } /** * Starts {@link BookActivity} intent with {@link ACTION_ADD_MANUAL} * <p> * Implements {@link ScanOrManualDialogFragment.ScanOrManualDialogListener} * * @param dialog dialog dialog that called this function */ @Override public void onDialogManualClick(DialogFragment dialog) { // launch addbook activity with no data Intent intent = new Intent(); intent.setClass(getApplicationContext(), BookActivity.class); intent.setAction(ACTION_ADD_MANUAL); startActivity(intent); } /** * Retrieves result and ISBN data (if present) from calling Activity and launches * {@link BookActivity} intent with {@link ACTION_ADD_ISBN} and ISBN payload data. * * @param requestCode The integer request code originally supplied to * startActivityForResult(), allowing you to identify who this result came from. * @param resultCode The integer result code returned by the child activity through its setResult() * @param intent data An Intent, which can return result data to the caller * (various data can be attached to Intent "extras"). */ @Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { if(resultCode == RESULT_CANCELED) { // User cancelled barcodescan, show a toast notification Context context = getApplicationContext(); Resources res = getResources(); CharSequence text = res.getString(R.string.scan_cancelled); int duration = Toast.LENGTH_LONG; Toast toast = Toast.makeText(context, text, duration); toast.show(); return; } else if(resultCode == RESULT_OK) { IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent); if (scanResult != null && scanResult.getContents() != null) { Intent newIntent = new Intent(); newIntent.setClass(getApplicationContext(), BookActivity.class); newIntent.setAction(ACTION_ADD_ISBN); newIntent.putExtra(EXTRA_ISBN, scanResult.getContents()); startActivity(newIntent); } } else assert false : "onActivityResult() unexpected resultCode: " + resultCode; return; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_view); listView = (ListView) findViewById(R.id.listView1); listView.setOnItemClickListener(this); BooksProvider = new BooksStorage(this); } @Override public void onResume() { super.onResume(); refreshOverview(); } @Override public void onStop(){ super.onStop(); mCursor.close(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main_view, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. Intent intent; switch(item.getItemId()) { case R.id.action_settings: intent = new Intent(getApplicationContext(), SettingsActivity.class); startActivity(intent); return true; case R.id.action_about: AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.about_title); Resources res = getResources(); String aboutMessage = res.getString(R.string.about_message, BOOKS_VERSION); builder.setMessage(aboutMessage); AlertDialog aboutDialog = builder.create(); aboutDialog.show(); TextView view = (TextView) aboutDialog.findViewById(android.R.id.message); view.setTextSize(12); return true; case R.id.action_add: DialogFragment dialog = new ScanOrManualDialogFragment(); dialog.show(getFragmentManager(), "scan_or_manual"); return true; case R.id.action_history: intent = new Intent(getApplicationContext(), HistoryActivity.class); startActivity(intent); return true; } return super.onOptionsItemSelected(item); } public void onItemClick(AdapterView<?> parent, View v, int position, long id) { // map position to _id in DB selectionIndex = (int) adapter.getItemId(position); DialogFragment dialog = new EditOrDeleteDialogFragment(); dialog.show(getFragmentManager(), "edit_or_delete"); } }