Java tutorial
/* * @copyright 2013 Philip Warner * @license GNU General Public License * * This file is part of Book Catalogue. * * Book Catalogue 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. * * Book Catalogue 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 Book Catalogue. If not, see <http://www.gnu.org/licenses/>. */ package com.eleybourn.bookcatalogue.dialogs; import java.io.File; import java.util.ArrayList; import java.util.Date; import android.app.Activity; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; import android.support.v4.app.FragmentActivity; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.widget.LinearLayout; import android.widget.RadioButton; import android.widget.TextView; import com.eleybourn.bookcatalogue.AdministrationLibraryThing; import com.eleybourn.bookcatalogue.Author; import com.eleybourn.bookcatalogue.CatalogueDBAdapter; import com.eleybourn.bookcatalogue.LibraryThingManager; import com.eleybourn.bookcatalogue.R; import com.eleybourn.bookcatalogue.Series; import com.eleybourn.bookcatalogue.goodreads.GoodreadsRegister; import com.eleybourn.bookcatalogue.utils.Logger; import com.eleybourn.bookcatalogue.utils.Utils; import com.eleybourn.bookcatalogue.utils.ViewTagger; public class StandardDialogs { /** * Show a dialog asking if unsaved edits should be ignored. Finish if so. */ public static void showConfirmUnsavedEditsDialog(final Activity a, final Runnable r) { AlertDialog.Builder dialog = new Builder(a); dialog.setTitle(R.string.details_have_changed); dialog.setMessage(R.string.you_have_unsaved_changes); dialog.setPositiveButton(R.string.exit, new AlertDialog.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); if (r != null) { r.run(); } else { a.finish(); } } }); dialog.setNegativeButton(R.string.continue_editing, new AlertDialog.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); dialog.setCancelable(false); dialog.create().show(); } public static void needLibraryThingAlert(final Context context, final boolean ltRequired, final String prefSuffix) { boolean showAlert; int msgId; final String prefName = LibraryThingManager.LT_HIDE_ALERT_PREF_NAME + "_" + prefSuffix; if (!ltRequired) { msgId = R.string.uses_library_thing_info; SharedPreferences prefs = context.getSharedPreferences("bookCatalogue", android.content.Context.MODE_PRIVATE); showAlert = !prefs.getBoolean(prefName, false); } else { msgId = R.string.require_library_thing_info; showAlert = true; } if (!showAlert) return; final AlertDialog dlg = new AlertDialog.Builder(context).setMessage(msgId).create(); dlg.setTitle(R.string.reg_library_thing_title); dlg.setIcon(android.R.drawable.ic_menu_info_details); dlg.setButton(DialogInterface.BUTTON_POSITIVE, context.getResources().getString(R.string.more_info), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Intent i = new Intent(context, AdministrationLibraryThing.class); context.startActivity(i); dlg.dismiss(); } }); if (!ltRequired) { dlg.setButton(DialogInterface.BUTTON_NEUTRAL, context.getResources().getString(R.string.disable_dialogue), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { SharedPreferences prefs = context.getSharedPreferences("bookCatalogue", android.content.Context.MODE_PRIVATE); SharedPreferences.Editor ed = prefs.edit(); ed.putBoolean(prefName, true); ed.commit(); dlg.dismiss(); } }); } dlg.setButton(DialogInterface.BUTTON_NEGATIVE, context.getResources().getString(R.string.cancel), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dlg.dismiss(); } }); dlg.show(); } public static void deleteSeriesAlert(Context context, final CatalogueDBAdapter dbHelper, final Series series, final Runnable onDeleted) { // When we get here, we know the names are genuinely different and the old series is used in more than one place. String message = "Delete series"; try { message = String.format(context.getResources().getString(R.string.really_delete_series), series.name); } catch (NullPointerException e) { Logger.logError(e); } final AlertDialog alertDialog = new AlertDialog.Builder(context).setMessage(message).create(); alertDialog.setTitle(R.string.delete_series); alertDialog.setIcon(android.R.drawable.ic_menu_info_details); //alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, context.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() { alertDialog.setButton2(context.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dbHelper.deleteSeries(series); alertDialog.dismiss(); onDeleted.run(); } }); //alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getResources().getString(R.string.cancel), new DialogInterface.OnClickListener() { alertDialog.setButton(context.getResources().getString(R.string.cancel), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { alertDialog.dismiss(); } }); alertDialog.show(); } public static int deleteBookAlert(Context context, final CatalogueDBAdapter dbHelper, final long id, final Runnable onDeleted) { ArrayList<Author> authorList = dbHelper.getBookAuthorList(id); String title; Cursor cur = dbHelper.fetchBookById(id); try { if (cur == null || !cur.moveToFirst()) return R.string.unable_to_find_book; title = cur.getString(cur.getColumnIndex(CatalogueDBAdapter.KEY_TITLE)); if (title == null || title.length() == 0) title = "<Unknown>"; } finally { if (cur != null) cur.close(); } // Format the list of authors nicely String authors; if (authorList.size() == 0) authors = "<Unknown>"; else { authors = authorList.get(0).getDisplayName(); for (int i = 1; i < authorList.size() - 1; i++) { authors += ", " + authorList.get(i).getDisplayName(); } if (authorList.size() > 1) authors += " " + context.getResources().getString(R.string.list_and) + " " + authorList.get(authorList.size() - 1).getDisplayName(); } // Get the title String format = context.getResources().getString(R.string.really_delete_book); String message = String.format(format, title, authors); final AlertDialog alertDialog = new AlertDialog.Builder(context).setMessage(message).create(); alertDialog.setTitle(R.string.menu_delete); alertDialog.setIcon(android.R.drawable.ic_menu_info_details); //alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, context.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() { alertDialog.setButton2(context.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dbHelper.deleteBook(id); alertDialog.dismiss(); onDeleted.run(); } }); //alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getResources().getString(R.string.cancel), new DialogInterface.OnClickListener() { alertDialog.setButton(context.getResources().getString(R.string.cancel), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { alertDialog.dismiss(); } }); alertDialog.show(); return 0; } /** * Display a dialog warning the user that goodreads authentication is required; gives them * the options: 'request now', 'more info' or 'cancel'. */ public static int goodreadsAuthAlert(final FragmentActivity context) { // Get the title final AlertDialog alertDialog = new AlertDialog.Builder(context).setTitle(R.string.authorize_access) .setMessage(R.string.goodreads_action_cannot_blah_blah).create(); alertDialog.setIcon(android.R.drawable.ic_menu_info_details); alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, context.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { alertDialog.dismiss(); GoodreadsRegister.requestAuthorizationInBackground(context); } }); alertDialog.setButton(DialogInterface.BUTTON_NEUTRAL, context.getResources().getString(R.string.tell_me_more), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { alertDialog.dismiss(); Intent i = new Intent(context, GoodreadsRegister.class); context.startActivity(i); } }); alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getResources().getString(R.string.cancel), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { alertDialog.dismiss(); } }); alertDialog.show(); return 0; } /** * Interface for item that displays in a custom dialog list */ public static interface SimpleDialogItem { View getView(LayoutInflater inflater); RadioButton getSelector(View v); } /** * Interface to listen for item selection in a custom dialog list */ public static interface SimpleDialogOnClickListener { void onClick(SimpleDialogItem item); } /** * Select a custom item from a list, and call halder when/if item is selected. */ public static void selectItemDialog(LayoutInflater inflater, String message, ArrayList<SimpleDialogItem> items, SimpleDialogItem selectedItem, final SimpleDialogOnClickListener handler) { // Get the view and the radio group final View root = inflater.inflate(R.layout.select_list_dialog, null); TextView msg = (TextView) root.findViewById(R.id.message); // Build the base dialog final AlertDialog.Builder builder = new AlertDialog.Builder(inflater.getContext()).setView(root); if (message != null && !message.equals("")) { msg.setText(message); } else { msg.setVisibility(View.GONE); } final AlertDialog dialog = builder.create(); // Create the listener for each item OnClickListener listener = new OnClickListener() { @Override public void onClick(View v) { SimpleDialogItem item = (SimpleDialogItem) ViewTagger.getTag(v, R.id.TAG_DIALOG_ITEM); // For a consistent UI, make sure the selector is checked as well. NOT mandatory from // a functional point of view, just consistent if (!(v instanceof RadioButton)) { RadioButton btn = item.getSelector(v); if (btn != null) { btn.setChecked(true); btn.invalidate(); } } // // It would be nice to have the other radio buttons reflect the new state before it // disappears, but not really worth the effort. Esp. since the code below does not work... // and the dialog disappears too fast to make this worthwhile. // //LinearLayout list = (LinearLayout)root.findViewById(R.id.list); //for(int i = 0; i < list.getChildCount(); i++) { // View child = list.getChildAt(i); // SimpleDialogItem other = (SimpleDialogItem)ViewTagger.getTag(child, R.id.TAG_DIALOG_ITEM); // RadioButton btn = other.getSelector(child); // btn.setSelected(other == item); // btn.invalidate(); //} dialog.dismiss(); handler.onClick(item); } }; // Add the items to the dialog LinearLayout list = (LinearLayout) root.findViewById(R.id.list); for (SimpleDialogItem item : items) { View v = item.getView(inflater); v.setBackgroundResource(android.R.drawable.list_selector_background); ViewTagger.setTag(v, R.id.TAG_DIALOG_ITEM, item); list.addView(v); v.setOnClickListener(listener); RadioButton btn = item.getSelector(v); if (btn != null) { ViewTagger.setTag(btn, R.id.TAG_DIALOG_ITEM, item); btn.setChecked(item == selectedItem); btn.setOnClickListener(listener); } } dialog.show(); } /** * Wrapper class to present a list of files for selection */ public static void selectFileDialog(LayoutInflater inflater, String title, ArrayList<File> files, final SimpleDialogOnClickListener handler) { ArrayList<SimpleDialogItem> items = new ArrayList<SimpleDialogItem>(); for (File file : files) { items.add(new SimpleDialogFileItem(file)); } selectItemDialog(inflater, title, items, null, handler); } /** * Wrapper class to present a list of arbitrary objects for selection; it uses * the toString() method to display a simple list. */ public static <T extends Object> void selectStringDialog(LayoutInflater inflater, String title, ArrayList<T> objects, String current, final SimpleDialogOnClickListener handler) { ArrayList<SimpleDialogItem> items = new ArrayList<SimpleDialogItem>(); SimpleDialogItem selectedItem = null; for (T o : objects) { SimpleDialogObjectItem item = new SimpleDialogObjectItem(o); if (current != null && o.toString().equalsIgnoreCase(current)) selectedItem = item; items.add(item); } selectItemDialog(inflater, title, items, selectedItem, handler); } /** * Simple item to manage a File object in a list of items. */ public static class SimpleDialogFileItem implements SimpleDialogItem { private final File mFile; public SimpleDialogFileItem(File file) { mFile = file; } public File getFile() { return mFile; } public RadioButton getSelector(View v) { return null; } /** * Get a View to display the file */ public View getView(LayoutInflater inflater) { // Create the view View v = inflater.inflate(R.layout.file_list_item, null); // Set the file name TextView name = (TextView) v.findViewById(R.id.name); name.setText(mFile.getName()); // Set the path TextView location = (TextView) v.findViewById(R.id.path); location.setText(mFile.getParent()); // Set the size TextView size = (TextView) v.findViewById(R.id.size); size.setText(Utils.formatFileSize(mFile.length())); // Set the last modified date TextView update = (TextView) v.findViewById(R.id.updated); update.setText(Utils.toPrettyDateTime(new Date(mFile.lastModified()))); // Return it return v; } } /** * Item to manage an Object in a list of items. */ public static class SimpleDialogObjectItem implements SimpleDialogItem { private final Object mObject; public SimpleDialogObjectItem(Object object) { mObject = object; } public Object getObject() { return mObject; } /** * Get a View to display the object */ public View getView(LayoutInflater inflater) { // Create the view View v = inflater.inflate(R.layout.string_list_item, null); // Set the name TextView name = (TextView) v.findViewById(R.id.name); name.setText(mObject.toString()); // Return it return v; } public RadioButton getSelector(View v) { return (RadioButton) v.findViewById(R.id.selector); } /** * Get the underlying object as a string */ @Override public String toString() { return mObject.toString(); } } public static class SimpleDialogMenuItem extends SimpleDialogObjectItem { final int mItemId; final int mDrawableId; public SimpleDialogMenuItem(Object object, int itemId, int icon) { super(object); mItemId = itemId; mDrawableId = icon; } public int getItemId() { return mItemId; } @Override public View getView(LayoutInflater inflater) { View v = super.getView(inflater); TextView name = (TextView) v.findViewById(R.id.name); name.setCompoundDrawablesWithIntrinsicBounds(mDrawableId, 0, 0, 0); getSelector(v).setVisibility(View.GONE); return v; } } }