Java tutorial
/* This code is released under MIT License (C) 2016-2017, Ezhil Language Foundation <ezhillang@gmail.com> */ package com.urbantamil.projmadurai; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Color; import android.graphics.Typeface; import android.media.Image; import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; import android.support.v4.app.Fragment; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.util.Log; 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.Button; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import org.json.JSONException; import com.google.android.gms.appindexing.Action; import com.google.android.gms.appindexing.AppIndex; import com.google.android.gms.appindexing.Thing; import com.tamil.TamilLetters; import com.tamil.utf8; import com.urbantamil.chithirai.TypefaceUtil; import com.urbantamil.chithirai.verbs.VerbContent; import com.urbantamil.projmadurai.MaduraiFilter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * An activity representing a list of Books. This activity * has different presentations for handset and tablet-size devices. On * handsets, the activity presents a list of items, which when touched, * lead to a {@link BookDetailActivity} representing * item details. On tablets, the activity presents the list of items and * item details side-by-side using two vertical panes. */ public class BookListActivity extends AppCompatActivity implements View.OnClickListener, MaduraiBookCoverFragment.OnFragmentInteractionListener { /** * Whether or not the activity is in two-pane mode, i.e. running on a tablet * device. */ private SimpleItemRecyclerViewAdapter adapter = null; private boolean mTwoPane; private MaduraiLibrary maduraiLibrary = null; private String TAG = "BookListAct"; private int m_filter_by = MaduraiFilter.FIELD_TITLE; //default public static final String ARG_FILTER_BY = "maduraifilter_BookListActivity_filter_by"; public static Typeface latha = null; private View recyclerView; private MaduraiPreferences mPref = null; MaduraiLibrary getMaduraiLibrary() { return maduraiLibrary; } void fireToast() { new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), R.string.projmad_please_wait, Toast.LENGTH_LONG).show(); } }.run(); } @Override public boolean onOptionsItemSelected(MenuItem item) { fireToast(); switch (item.getItemId()) { case R.id.menu_clear_all: do_clear_action(); break; case R.id.menu_sort_ascending: do_sort(true); break; case R.id.menu_sort_descending: do_sort(false); break; } return super.onOptionsItemSelected(item); } private void do_sort(boolean ascending) { // adapter.setupSortedList(ascending); // adapter.notifyDataSetChanged(); // lazy way out! quick too.. adapter.updateSortedList(ascending); recyclerView.postInvalidate(); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater mnu = new MenuInflater(getApplicationContext()); if (inBookmarkMode() || inRecentBookMode()) { mnu.inflate(R.menu.clear_menu, menu); } else { mnu.inflate(R.menu.sort_menu, menu); } return super.onCreateOptionsMenu(menu); } @Override protected void onCreate(Bundle savedInstanceState) { Bundle b = getIntent().getExtras(); mPref = new MaduraiPreferences(this); if (latha == null) latha = TypefaceUtil.getTypeface(TypefaceUtil.LATHA, getApplicationContext()); if (b != null) { m_filter_by = b.getInt(ARG_FILTER_BY, MaduraiFilter.FIELD_TITLE); } super.onCreate(savedInstanceState); Log.d(TAG, "m_filter_by => " + String.valueOf(m_filter_by)); setContentView(R.layout.activity_book_list); try { maduraiLibrary = MaduraiBook.loadFromAsset(getResources(), R.raw.projmad); } catch (Exception e) { Log.d(TAG, e.toString()); } Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); //hide this button - replace with menu Button bklist_sort_btn = (Button) findViewById(R.id.projmad_sort_button); bklist_sort_btn.setOnClickListener(this); bklist_sort_btn.setVisibility(View.INVISIBLE); if (m_filter_by == MaduraiFilter.FIELD_TITLE) { toolbar.setTitle(R.string.projmad_books); } else if (m_filter_by == MaduraiFilter.FIELD_AUTHOR) { toolbar.setTitle(R.string.projmad_authors); } else if (m_filter_by == MaduraiFilter.FIELD_BOOKMARK) { toolbar.setTitle(R.string.projmad_bookmarks); //bklist_sort_btn.setVisibility(View.VISIBLE); bklist_sort_btn.setText(R.string.projmad_clear_saved); } else if (m_filter_by == MaduraiFilter.FIELD_RECENTBOOK) { toolbar.setTitle(R.string.projmad_recentbooks); //bklist_sort_btn.setVisibility(View.VISIBLE); bklist_sort_btn.setText(R.string.projmad_clear_saved); } else if (m_filter_by == MaduraiFilter.FIELD_LASTREAD) { // just popup the last read book // get last most-recent read book and pop it open in the activity // FIXME MaduraiBook recent = MaduraiRecentBook.getManager(getParent()).getMostRecent(); if (recent == null) { Toast.makeText(this, R.string.projmad_recentbooks_empty, Toast.LENGTH_LONG); new Runnable() { @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } finish(); } }.run(); return; } Intent intent = new Intent(getApplicationContext(), BookDetailActivity.class); try { intent.putExtra(BookDetailFragment.ARG_ITEM_JSON, recent.SaveToJSON()); intent.putExtra(BookDetailFragment.ARG_ITEM_OPEN, true); } catch (Exception e) { //pass } startActivity(intent); finish(); return; } setTitle(toolbar.getTitle()); recyclerView = findViewById(R.id.book_list); assert recyclerView != null; setupRecyclerView((RecyclerView) recyclerView); if (findViewById(R.id.book_detail_container) != null) { // The detail container view will be present only in the // large-screen layouts (res/values-w900dp). // If this view is present, then the // activity should be in two-pane mode. mTwoPane = true; } } private void setupRecyclerView(@NonNull RecyclerView recyclerView) { adapter = new SimpleItemRecyclerViewAdapter(); new Runnable() { @Override public void run() { adapter.setupSortedList(true); } }.run(); recyclerView.setAdapter(adapter); //feedback to the user on number of items - Total Items Toast.makeText(getApplicationContext(), getString(R.string.MessageTotalItems) + adapter.getItemCount(), Toast.LENGTH_LONG).show(); } @Override public void onClick(View v) { Button btn = (Button) v; do_clear_action(); v.postInvalidate(); } private void do_clear_action() { if (m_filter_by == MaduraiFilter.FIELD_BOOKMARK) { MaduraiBookmark.getManager(getParent()).erase(); Log.d(TAG, "clear bookmark"); this.adapter.clear(); //update storage too! TBD } else if (m_filter_by == MaduraiFilter.FIELD_RECENTBOOK) { MaduraiRecentBook.getManager(getParent()).erase(); Log.d(TAG, "clear recent books"); this.adapter.clear(); //update storage too! } else { //change sort order adapter.flipOrder(); } //notify all involved in the process adapter.notifyDataSetChanged(); recyclerView.postInvalidate(); } @Override public void onStart() { super.onStart(); } @Override public void onStop() { super.onStop(); } boolean inGenreMode() { return (m_filter_by == MaduraiFilter.FIELD_GENRE); } boolean inBookmarkMode() { return (m_filter_by == MaduraiFilter.FIELD_BOOKMARK); } boolean inRecentBookMode() { return (m_filter_by == MaduraiFilter.FIELD_RECENTBOOK); } @Override public void onFragmentInteraction(Uri uri) { } private static final int animal_ids[] = new int[] { R.drawable.img_1, R.drawable.img_2, R.drawable.img_3, R.drawable.img_4, R.drawable.img_5, R.drawable.img_6, R.drawable.img_7, R.drawable.img_8, R.drawable.img_9, R.drawable.img_10, R.drawable.img_11, R.drawable.img_12, R.drawable.img_13, R.drawable.img_14, R.drawable.img_15, R.drawable.img_16, R.drawable.img_17, R.drawable.img_18, R.drawable.img_19, R.drawable.img_20, R.drawable.img_21, R.drawable.img_22, R.drawable.img_23, R.drawable.img_24, R.drawable.img_25, R.drawable.img_26, R.drawable.img_27, R.drawable.img_28, R.drawable.img_29, R.drawable.img_30, R.drawable.img_31, R.drawable.img_32, R.drawable.img_33, R.drawable.img_34, R.drawable.img_35, R.drawable.img_36, R.drawable.img_37, R.drawable.img_38, R.drawable.img_39, R.drawable.img_40 }; public static final short colors_rgba[][] = new short[][] { { 85, 19, 93, 255 }, { 113, 112, 110, 255 }, { 128, 27, 42, 255 }, { 184, 7, 33, 255 }, { 101, 22, 28, 255 }, { 80, 61, 189, 255 }, { 225, 17, 5, 255 }, { 6, 123, 176, 255 }, { 247, 181, 0, 255 }, { 0, 15, 118, 255 }, { 168, 0, 155, 255 }, { 0, 132, 69, 255 }, { 0, 153, 157, 255 }, { 1, 66, 132, 255 }, { 177, 0, 52, 255 }, { 55, 142, 25, 255 }, { 133, 152, 0, 255 } }; private static final int MAX_ANIMALS = 40; private static final int MAX_COLORS = colors_rgba.length; public class SimpleItemRecyclerViewAdapter extends RecyclerView.Adapter<SimpleItemRecyclerViewAdapter.ViewHolder> { private String TAG = "ItemViewAdapter"; private MaduraiLibrary maduraiLibrary; private boolean m_adapterSortedAscending = true; private String mTitle; private String mTopText; private String mAuthor; private String mAnimalCode; private String mColorCode; private String mGuideText; private ArrayList<String> genre_list = null; final private ArrayList<Object> sort_lookup = new ArrayList<Object>(); private String getGenreColorCode(String genre) { int pos = Collections.binarySearch(genre_list, genre, utf8.comparator); pos = Math.max(pos, 0); // 0-based return String.valueOf(pos % MAX_COLORS); } private String getGenreAnimalCode(String genre) { int pos = Collections.binarySearch(genre_list, genre, utf8.comparator); pos = Math.max(pos, 0); // 0-based return String.valueOf(pos % MAX_ANIMALS); } public SimpleItemRecyclerViewAdapter() { if (genre_list == null) { MaduraiLibrary mlib = MaduraiBook.loadFromAssetDefault(); genre_list = mlib.getGenresList(); TamilLetters.sort(genre_list); } maduraiLibrary = getMaduraiLibrary(); } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View rootV = inflater.inflate(R.layout.book_list_content, parent, false); ViewHolder rootVH = new ViewHolder(rootV); return rootVH; } // map the item at #position to the viewholder @Override public void onBindViewHolder(final ViewHolder holder, final int position) { MaduraiBook mBook = null; String genre = null; Log.d(TAG, "Total size of lookup array => " + String.valueOf(sort_lookup.size())); // request row alternation ?? if (mPref.getRowAlternate()) { if (position % 2 == 1) { holder.mView.setBackgroundColor(Color.BLUE); holder.mView.getBackground().setAlpha(100); } else { holder.mView.setBackgroundColor(Color.BLUE); holder.mView.getBackground().setAlpha(51); } } //set row # (min row = 1) holder.mRowPos.setText(String.valueOf(1 + position)); if (inGenreMode()) { genre = (String) sort_lookup.get(position); setupGenreView(genre, holder); return; } mBook = (MaduraiBook) sort_lookup.get(position); holder.mItem = mBook; mTitle = mBook.getTitle(); mTopText = getResources().getString(R.string.projmad_bookcover_toptext); mAuthor = mBook.getAuthor(); mAnimalCode = getGenreAnimalCode(mBook.getGenre()); mGuideText = mBook.getGenre(); mColorCode = getGenreColorCode(mBook.getGenre()); short[] rgba = colors_rgba[Integer.valueOf(mColorCode)]; int bgcolor = Color.argb(rgba[3], rgba[0], rgba[1], rgba[2]); holder.mFloatbar.setBackgroundColor(bgcolor); holder.mAnimal.setImageResource(animal_ids[Integer.valueOf(mAnimalCode)]); holder.mView.setBackgroundColor(bgcolor ^ 0x00FFFFFF); if (m_filter_by == MaduraiFilter.FIELD_AUTHOR) { holder.mIdView.setText(mBook.getAuthor()); holder.mContentView.setText(mBook.getTitle()); } else { holder.mIdView.setText(mBook.getTitle()); holder.mContentView.setText(mBook.getAuthor()); } //holder.mRowPos.setVisibility(View.INVISIBLE); holder.mView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { if (mTwoPane) { Bundle arguments = new Bundle(); arguments.putString(BookDetailFragment.ARG_ITEM_JSON, holder.mItem.SaveToJSON()); BookDetailFragment fragment = new BookDetailFragment(); fragment.setArguments(arguments); getSupportFragmentManager().beginTransaction() .replace(R.id.book_detail_container, fragment).commit(); } else { Context context = v.getContext(); Intent intent = new Intent(context, BookDetailActivity.class); intent.putExtra(BookDetailFragment.ARG_ITEM_JSON, holder.mItem.SaveToJSON()); context.startActivity(intent); } } catch (Exception e) { Log.d(TAG, "Failed to serialize JSON for object mItem with error \n->" + e.toString()); } } }); //allow deleting books if necessary from the said lists if (inRecentBookMode() || inBookmarkMode()) { holder.mView.setTag(holder); holder.mView.setOnLongClickListener(new View.OnLongClickListener() { final int rel_position = position; @Override public boolean onLongClick(View v) { OKCancelDialog dlg = new OKCancelDialog(); getSupportFragmentManager().beginTransaction().add(dlg, "OK_CANCEL_DIALOG").commit(); //already shown the dialog here.. boolean OK = dlg.m_OK; if (!OK) { Log.d(TAG, "Cancelled deletion item"); return true; } if (inRecentBookMode()) { MaduraiRecentBook.getManager(getParent()).remove(rel_position); } else if (inBookmarkMode()) { MaduraiBookmark.getManager(getParent()).remove(rel_position); } Log.d(TAG, "removed item @ " + String.valueOf(rel_position)); View recycler = findViewById(R.id.book_list); recycler.invalidate(); adapter.notifyDataSetChanged(); return true; //handled the event OK so far } }); } } private void setupGenreView(String arg_genre, ViewHolder holder) { final String genre = arg_genre; holder.mIdView.setText(genre); holder.mContentView.setText(GenreDescription.get(genre)); holder.mIdView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //open the search view with the category set to 'genre' etc. Context context = v.getContext(); Intent intent = new Intent(context, MaduraiSearch.class); intent.putExtra(MaduraiSearch.ARG_ITEM_GENRE, genre); context.startActivity(intent); } }); mColorCode = getGenreColorCode(arg_genre); mAnimalCode = getGenreAnimalCode(arg_genre); short[] rgba = colors_rgba[Integer.valueOf(mColorCode)]; int bgcolor = Color.argb(rgba[3], rgba[0], rgba[1], rgba[2]); holder.mFloatbar.setBackgroundColor(bgcolor) ; holder.mAnimal.setImageResource(animal_ids[Integer.valueOf(mAnimalCode)]); holder.mView.setBackgroundColor(bgcolor ^ 0x00FFFFFF); } private void flipOrder() { Collections.reverse(sort_lookup); } private Object getObject(int idx) { Object book_or_str = null; if (inBookmarkMode()) book_or_str = MaduraiBookmark.getManager(getParent()).getBookAt(idx); else if (inRecentBookMode()) book_or_str = MaduraiRecentBook.getManager(getParent()).getBookAt(idx); else if (inGenreMode()) book_or_str = getMaduraiLibrary().getGenresList().get(idx); else book_or_str = maduraiLibrary.getBookAt(idx); return book_or_str; } private void updateSortedList(boolean is_ascending) { if (m_adapterSortedAscending == is_ascending) return; //reverse the list if current state don't match flipOrder(); m_adapterSortedAscending = is_ascending; notifyDataSetChanged(); } private void setupSortedList(final boolean ascending) { m_adapterSortedAscending = ascending; sort_lookup.clear(); for (int idx = 0; idx < getItemCount(); idx++) { Object book_or_str = getObject(idx); sort_lookup.add(book_or_str); } Log.d(TAG, "sort_lookup has size => " + sort_lookup.size()); // no sorting for recent book mode if (inRecentBookMode()) return; if (inGenreMode()) { //compare by genre new Runnable() { @Override public void run() { final boolean ascend = ascending; Collections.sort(sort_lookup, new Comparator<Object>() { @Override public int compare(Object lhs, Object rhs) { String s_lhs = (String) lhs; String s_rhs = (String) rhs; return ascend ? s_lhs.compareTo(s_rhs) : s_rhs.compareTo(s_rhs); } }); } }.run(); } else { int mode = 0; if (m_filter_by == MaduraiFilter.FIELD_TITLE) { mode = MaduraiBookComparator.TITLE; } else if (m_filter_by == MaduraiFilter.FIELD_AUTHOR) { mode = MaduraiBookComparator.AUTHOR; } else if (m_filter_by == MaduraiFilter.FIELD_RECENTBOOK || m_filter_by == MaduraiFilter.FIELD_BOOKMARK) { mode = MaduraiBookComparator.TITLE; } else { mode = MaduraiBookComparator.TITLE; } final MaduraiBookComparator maduraiBookComparator = new MaduraiBookComparator(mode); new Runnable() { @Override public void run() { final boolean ascend = ascending; Collections.sort(sort_lookup, new Comparator<Object>() { @Override public int compare(Object lhs, Object rhs) { if (ascend) { return maduraiBookComparator.compare((MaduraiBook) lhs, (MaduraiBook) rhs); } return maduraiBookComparator.compare((MaduraiBook) rhs, (MaduraiBook) lhs); } } ); } }.run(); } this.notifyDataSetChanged(); } @Override public int getItemCount() { int size = 0; if (inBookmarkMode()) size = MaduraiBookmark.getManager(getParent()).size(); else if (inRecentBookMode()) size = MaduraiRecentBook.getManager(getParent()).size(); else if (inGenreMode()) size = getMaduraiLibrary().getGenresList().size(); else size = maduraiLibrary.size(); return (int) size; } public void clear() { sort_lookup.clear(); if (inBookmarkMode()) MaduraiBookmark.getManager(getParent()).erase(); else if (inRecentBookMode()) MaduraiRecentBook.getManager(getParent()).erase(); } public class ViewHolder extends RecyclerView.ViewHolder { public final View mView; public final TextView mIdView; public final TextView mContentView; public final TextView mRowPos; public MaduraiBook mItem; public final ImageView mAnimal; public final View mFloatbar; public ViewHolder(View rootV) { super(rootV); mView = (View) rootV.findViewById(R.id.id_parent); mIdView = (TextView) rootV.findViewById(R.id.id); mContentView = (TextView) rootV.findViewById(R.id.content); mRowPos = (TextView) rootV.findViewById(R.id.row_pos); mFloatbar = (View) rootV.findViewById(R.id.projmad_list_bookcover_floatbar_top); TextView toptext = (TextView) rootV.findViewById(R.id.projmad_list_bookcover_toptext); toptext.setText(mTopText); TextView author = (TextView) rootV.findViewById(R.id.projmad_list_bookcover_author_name); author.setText(mAuthor); TextView title = (TextView) rootV.findViewById(R.id.projmad_list_bookcover_title); title.setText(mTitle); TextView guide = (TextView) rootV.findViewById(R.id.projmad_list_bookcover_guide_text); guide.setText(mGuideText); mAnimal = (ImageView) rootV.findViewById(R.id.projmad_list_bookcover_animal_image); // intialize with Latha font mIdView.setTypeface(latha, Typeface.BOLD); mContentView.setTypeface(latha, Typeface.ITALIC); } @Override public String toString() { return super.toString() + " '" + mContentView.getText() + "'"; } } } }