/* * Copyright (C) 2009 Muthu Ramadoss. All rights reserved. * * Modified from Romain Guy Shelves project to suit Books-Exchange requirements. * Original source from Shelves - http://code.google.com/p/shelves/ */ /* * Copyright (C) 2009 Romain Guy * * 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 com.androidrocks.bex.activity; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.os.Bundle; import android.content.Context; import android.content.Intent; import android.content.DialogInterface; import android.view.View; import android.view.ViewStub; import android.view.ViewGroup; import android.view.LayoutInflater; import android.view.animation.AnimationUtils; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.ListView; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.AdapterView; import android.text.TextWatcher; import android.text.Editable; import android.text.TextUtils; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import com.androidrocks.bex.drawable.FastBitmapDrawable; import com.androidrocks.bex.provider.BookStoreFactory; import com.androidrocks.bex.provider.BooksManager; import com.androidrocks.bex.provider.BooksStore; import com.androidrocks.bex.util.ImageUtilities; import com.androidrocks.bex.util.TextUtilities; import com.androidrocks.bex.util.UIUtilities; import com.androidrocks.bex.util.UserTask; import com.androidrocks.bex.R; import java.util.ArrayList; public class AddBookActivity extends Activity implements View.OnClickListener, AdapterView.OnItemClickListener { private static final int BOOK_COVER_WIDTH = 70; private static final int BOOK_COVER_HEIGHT = 70; private static final int DIALOG_ADD = 1; private static final String STATE_ADD_IN_PROGRESS = "shelves.add.inprogress"; private static final String STATE_ADD_BOOK = "shelves.add.book"; private static final String STATE_SEARCH_IN_PROGRESS = "shelves.search.inprogress"; private static final String STATE_SEARCH_QUERY = "shelves.search.book"; private static final String STATE_BOOK_TO_ADD = "shelves.add.bookToAdd"; private SearchTask mSearchTask; private AddTask mAddTask; private View mSearchButton; private EditText mSearchQuery; private View mSearchPanel; private View mAddPanel; private SearchResultsAdapter mBooksAdapter; private BooksStore.Book mBookToAdd; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.screen_add_search); setupViews(); } static void show(Context context) { final Intent intent = new Intent(context, AddBookActivity.class); context.startActivity(intent); } private void setupViews() { mSearchButton = findViewById(R.id.button_go); mSearchButton.setOnClickListener(this); mSearchButton.setEnabled(false); mSearchQuery = (EditText) findViewById(R.id.input_search_query); mSearchQuery.addTextChangedListener(new SearchFieldWatcher()); final FastBitmapDrawable cover = new FastBitmapDrawable(ImageUtilities.createShadow( BitmapFactory.decodeResource(getResources(), R.drawable.unknown_cover_no_shadow), BOOK_COVER_WIDTH, BOOK_COVER_HEIGHT)); mBooksAdapter = new SearchResultsAdapter(this, cover); final SearchResultsAdapter resultsAdapter = mBooksAdapter; final SearchResultsAdapter oldAdapter = (SearchResultsAdapter) getLastNonConfigurationInstance(); if (oldAdapter != null) { final int count = oldAdapter.getCount(); for (int i = 0; i < count; i++) { resultsAdapter.add(oldAdapter.getItem(i)); } } final ListView searchResults = (ListView) findViewById(R.id.list_search_results); searchResults.setAdapter(resultsAdapter); searchResults.setOnItemClickListener(this); } @Override protected void onDestroy() { super.onDestroy(); onCancelAdd(); onCancelSearch(); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); restoreBookToAdd(savedInstanceState); restoreAddTask(savedInstanceState); restoreSearchTask(savedInstanceState); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if (isFinishing()) { saveBookToAdd(outState); saveAddTask(outState); saveSearchTask(outState); } } @Override public Object onRetainNonConfigurationInstance() { return mBooksAdapter; } private void saveBookToAdd(Bundle outState) { if (mBookToAdd != null) { outState.putParcelable(STATE_BOOK_TO_ADD, mBookToAdd); } } private void restoreBookToAdd(Bundle savedInstanceState) { final Object data = savedInstanceState.get(STATE_BOOK_TO_ADD); if (data != null) { mBookToAdd = (BooksStore.Book) data; } } private void saveAddTask(Bundle outState) { final AddTask task = mAddTask; if (task != null && task.getStatus() != UserTask.Status.FINISHED) { final String bookId = task.getBookId(); task.cancel(true); if (bookId != null) { outState.putBoolean(STATE_ADD_IN_PROGRESS, true); outState.putString(STATE_ADD_BOOK, bookId); } mAddTask = null; } } private void restoreAddTask(Bundle savedInstanceState) { if (savedInstanceState.getBoolean(STATE_ADD_IN_PROGRESS)) { final String id = savedInstanceState.getString(STATE_ADD_BOOK); if (!BooksManager.bookExists(getContentResolver(), id)) { mAddTask = (AddTask) new AddTask().execute(id); } } } private void saveSearchTask(Bundle outState) { final SearchTask task = mSearchTask; if (task != null && task.getStatus() != UserTask.Status.FINISHED) { final String bookId = task.getQuery(); task.cancel(true); if (bookId != null) { outState.putBoolean(STATE_SEARCH_IN_PROGRESS, true); outState.putString(STATE_SEARCH_QUERY, bookId); } mSearchTask = null; } } private void restoreSearchTask(Bundle savedInstanceState) { if (savedInstanceState.getBoolean(STATE_SEARCH_IN_PROGRESS)) { final String query = savedInstanceState.getString(STATE_SEARCH_QUERY); if (!TextUtils.isEmpty(query)) { mSearchTask = (SearchTask) new SearchTask().execute(query); } } } public void onItemClick(AdapterView<?> parent, View view, int position, long id) { mBookToAdd = mBooksAdapter.getItem(position).book; showDialog(DIALOG_ADD); } @Override protected Dialog onCreateDialog(int id) { switch (id) { case DIALOG_ADD: final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(mBookToAdd != null ? mBookToAdd.getTitle() : " "); builder.setIcon(android.R.drawable.ic_dialog_alert); builder.setMessage(R.string.dialog_add_message); builder.setPositiveButton(R.string.dialog_add_ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { String bookId = mBookToAdd.getEan(); if (bookId == null) bookId = mBookToAdd.getIsbn(); if (bookId == null) bookId = mBookToAdd.getInternalIdNoPrefix(); onAdd(bookId); mBookToAdd = null; } }); builder.setNegativeButton(R.string.dialog_add_cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { mBookToAdd = null; dismissDialog(DIALOG_ADD); } }); builder.setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { mBookToAdd = null; dismissDialog(DIALOG_ADD); } }); builder.setCancelable(true); return builder.create(); } return super.onCreateDialog(id); } @Override protected void onPrepareDialog(int id, Dialog dialog) { super.onPrepareDialog(id, dialog); switch (id) { case DIALOG_ADD: dialog.setTitle(mBookToAdd.getTitle()); break; } } public void onClick(View v) { switch (v.getId()) { case R.id.button_go: onSearch(); break; } } private void onSearch() { if (mSearchTask == null || mSearchTask.getStatus() == SearchTask.Status.FINISHED) { mSearchTask = (SearchTask) new SearchTask().execute(mSearchQuery.getText().toString()); } else { UIUtilities.showToast(this, R.string.error_search_in_progress); } } private void onCancelSearch() { if (mSearchTask != null && mSearchTask.getStatus() == UserTask.Status.RUNNING) { mSearchTask.cancel(true); mSearchTask = null; } } private void onAdd(String id) { if (!BooksManager.bookExists(getContentResolver(), id)) { mAddTask = (AddTask) new AddTask().execute(id); } else { UIUtilities.showToast(this, R.string.error_book_exists); } } private void onCancelAdd() { if (mAddTask != null && mAddTask.getStatus() == UserTask.Status.RUNNING) { mAddTask.cancel(true); mAddTask = null; } } private void showPanel(View panel, boolean slideUp) { panel.startAnimation(AnimationUtils.loadAnimation(this, slideUp ? R.anim.slide_in : R.anim.slide_out_top)); panel.setVisibility(View.VISIBLE); } private void hidePanel(View panel, boolean slideDown) { panel.startAnimation(AnimationUtils.loadAnimation(this, slideDown ? R.anim.slide_out : R.anim.slide_in_top)); panel.setVisibility(View.GONE); } private void disableSearchPanel() { mSearchButton.setEnabled(false); mSearchQuery.setEnabled(false); } private void enableSearchPanel() { mSearchButton.setEnabled(true); mSearchQuery.setEnabled(true); } private class AddTask extends UserTask<String, Void, BooksStore.Book> { private final Object mLock = new Object(); private String mBookId; private FastBitmapDrawable mDefaultCover; @Override public void onPreExecute() { final Bitmap defaultCoverBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.unknown_cover); mDefaultCover = new FastBitmapDrawable(defaultCoverBitmap); if (mAddPanel == null) { mAddPanel = ((ViewStub) findViewById(R.id.stub_add)).inflate(); ((ProgressBar) mAddPanel.findViewById(R.id.progress)).setIndeterminate(true); final View cancelButton = mAddPanel.findViewById(R.id.button_cancel); cancelButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { onCancelAdd(); } }); } disableSearchPanel(); showPanel(mAddPanel, false); } String getBookId() { synchronized (mLock) { return mBookId; } } public BooksStore.Book doInBackground(String... params) { synchronized (mLock) { mBookId = params[0]; } return BooksManager.loadAndAddBook(getContentResolver(), mBookId, BookStoreFactory.get(AddBookActivity.this)); } @Override public void onCancelled() { enableSearchPanel(); hidePanel(mAddPanel, false); } @Override public void onPostExecute(BooksStore.Book book) { enableSearchPanel(); if (book == null) { UIUtilities.showToast(AddBookActivity.this, R.string.error_adding_book); } else { UIUtilities.showFormattedImageToast(AddBookActivity.this, R.string.success_added, ImageUtilities.getCachedCover(book.getInternalId(), mDefaultCover), book.getTitle()); } hidePanel(mAddPanel, false); } } private class SearchTask extends UserTask<String, ResultBook, Void> implements BooksStore.BookSearchListener { private final Object mLock = new Object(); private String mQuery; @Override public void onPreExecute() { disableSearchPanel(); if (mSearchPanel == null) { mSearchPanel = ((ViewStub) findViewById(R.id.stub_search)).inflate(); ProgressBar progress = (ProgressBar) mSearchPanel.findViewById(R.id.progress); progress.setIndeterminate(true); ((TextView) findViewById(R.id.label_import)).setText(R.string.search_progress); final View cancelButton = mSearchPanel.findViewById(R.id.button_cancel); cancelButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { onCancelSearch(); } }); } mBooksAdapter.clear(); showPanel(mSearchPanel, true); } String getQuery() { synchronized (mLock) { return mQuery; } } public Void doInBackground(String... params) { synchronized (mLock) { mQuery = params[0]; } BookStoreFactory.get(AddBookActivity.this).searchBooks(mQuery, this); return null; } @Override public void onProgressUpdate(ResultBook... values) { for (ResultBook book : values) { mBooksAdapter.add(book); } } @Override public void onPostExecute(Void ignore) { enableSearchPanel(); UIUtilities.showFormattedToast(AddBookActivity.this, R.string.success_found, mBooksAdapter.getCount()); hidePanel(mSearchPanel, true); } @Override public void onCancelled() { enableSearchPanel(); hidePanel(mSearchPanel, true); } public void onBookFound(BooksStore.Book book, ArrayList<BooksStore.Book> books) { if (book != null && !isCancelled()) { publishProgress(new ResultBook(book)); } } } private class SearchFieldWatcher implements TextWatcher { public void beforeTextChanged(CharSequence s, int start, int count, int after) { } public void onTextChanged(CharSequence s, int start, int before, int count) { mSearchButton.setEnabled(s.length() > 0); } public void afterTextChanged(Editable s) { } } private static class SearchResultsAdapter extends ArrayAdapter<ResultBook> { private final LayoutInflater mLayoutInflater; private final FastBitmapDrawable mDefaultCover; SearchResultsAdapter(AddBookActivity activity, FastBitmapDrawable cover) { super(activity, 0); mDefaultCover = cover; mLayoutInflater = LayoutInflater.from(activity); } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { convertView = mLayoutInflater.inflate(R.layout.search_result_book, parent, false); holder = new ViewHolder(); holder.cover = (ImageView) convertView.findViewById(R.id.image_cover); holder.title = (TextView) convertView.findViewById(R.id.label_title); holder.author = (TextView) convertView.findViewById(R.id.label_author); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } final ResultBook book = getItem(position); holder.book = book.book; holder.title.setText(book.title); holder.author.setText(book.authors); final boolean hasCover = book.cover != null; holder.cover.setImageDrawable(hasCover ? book.cover : mDefaultCover); return convertView; } } private static class ViewHolder { ImageView cover; TextView title; TextView author; BooksStore.Book book; } private static class ResultBook { final BooksStore.Book book; final String text; final String title; final String authors; final FastBitmapDrawable cover; ResultBook(BooksStore.Book book) { this.book = book; Bitmap bitmap = ImageUtilities.createShadow( book.loadCover(BooksStore.ImageSize.THUMBNAIL), BOOK_COVER_WIDTH, BOOK_COVER_HEIGHT); if (bitmap != null) { cover = new FastBitmapDrawable(bitmap); } else { cover = null; } title = book.getTitle(); authors = TextUtilities.join(book.getAuthors(), ", "); text = title + ' ' + authors; } @Override public String toString() { return text; } } }