package com.erakk.lnreader.UI.fragment; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.ExpandableListView; import android.widget.ExpandableListView.OnChildClickListener; import android.widget.ImageView; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; import com.erakk.lnreader.Constants; import com.erakk.lnreader.LNReaderApplication; import com.erakk.lnreader.R; import com.erakk.lnreader.UI.activity.DisplayImageActivity; import com.erakk.lnreader.UI.activity.DisplayLightNovelContentActivity; import com.erakk.lnreader.UIHelper; import com.erakk.lnreader.adapter.BookModelAdapter; import com.erakk.lnreader.callback.ICallbackEventData; import com.erakk.lnreader.callback.IExtendedCallbackNotifier; import com.erakk.lnreader.dao.NovelsDao; import com.erakk.lnreader.helper.Util; import com.erakk.lnreader.model.BookModel; import com.erakk.lnreader.model.NovelCollectionModel; import com.erakk.lnreader.model.NovelContentModel; import com.erakk.lnreader.model.PageModel; import com.erakk.lnreader.parser.CommonParser; import com.erakk.lnreader.task.AsyncTaskResult; import com.erakk.lnreader.task.DownloadNovelContentTask; import com.erakk.lnreader.task.LoadNovelDetailsTask; import java.net.URL; import java.util.ArrayList; public class DisplayLightNovelDetailsFragment extends Fragment implements IExtendedCallbackNotifier<AsyncTaskResult<?>> { public static final String TAG = DisplayLightNovelDetailsFragment.class.toString(); private PageModel page; private NovelCollectionModel novelCol; private final NovelsDao dao = NovelsDao.getInstance(); private BookModelAdapter bookModelAdapter; private ExpandableListView expandList; private DownloadNovelContentTask downloadTask = null; private LoadNovelDetailsTask task = null; private TextView loadingText; private ProgressBar loadingBar; private String touchedForDownload; @Override public void onAttach(Activity activity) { super.onAttach(activity); // Get intent and message page = new PageModel(); String pageStr = getArguments().getString(Constants.EXTRA_PAGE); String title = getArguments().getString(Constants.EXTRA_TITLE); if (Util.isStringNullOrEmpty(pageStr)) { Log.w(TAG, "Page is empty!"); } page.setPage(pageStr); try { page = dao.getPageModel(page, null); } catch (Exception e) { Log.e(TAG, "Failed to get pagemodel for: " + pageStr, e); } getActivity().setTitle(title); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_display_light_novel_details, container, false); loadingText = (TextView) view.findViewById(R.id.emptyList); loadingBar = (ProgressBar) view.findViewById(R.id.empttListProgress); // setup listener expandList = (ExpandableListView) view.findViewById(R.id.chapter_list); registerForContextMenu(expandList); expandList.setOnChildClickListener(new OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { if (novelCol != null) { PageModel chapter = bookModelAdapter.getChild(groupPosition, childPosition); String bookName = novelCol.getBookCollections().get(groupPosition).getTitle(); touchedForDownload = bookName + " " + chapter.getTitle(); loadChapter(chapter); } return false; } }); setHasOptionsMenu(true); executeTask(page, false); return view; } @Override public void onResume() { super.onResume(); Log.d(TAG, "OnResume: " + task.getStatus().toString()); final Activity activity = getActivity(); new Handler().post(new Runnable() { @Override public void run() { // try to refresh on different thread if (bookModelAdapter != null) { bookModelAdapter.refreshData(); activity.runOnUiThread(new Runnable() { @Override public void run() { bookModelAdapter.notifyDataSetChanged(); if (expandList != null) { expandList.invalidateViews(); } } }); } } }); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.fragment_display_light_novel_details, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { Log.d(TAG, "menu Option called."); switch (item.getItemId()) { case R.id.menu_refresh_chapter_list: Log.d(TAG, "Refreshing Details"); executeTask(page, true); Toast.makeText(getActivity(), getResources().getString(R.string.refreshing_detail), Toast.LENGTH_SHORT).show(); return true; case R.id.menu_details_download_all: /* * Download all chapters */ if (novelCol == null) return true; ArrayList<PageModel> availableChapters = novelCol.getFlattedChapterList(); ArrayList<PageModel> notDownloadedChapters = new ArrayList<PageModel>(); for (PageModel pageModel : availableChapters) { // add to the list if not missing and not external if (!pageModel.isMissing() && !pageModel.isExternal()) // and not yet downloaded or got updates. if (!pageModel.isDownloaded() || dao.isContentUpdated(pageModel)) { notDownloadedChapters.add(pageModel); Log.d(TAG, "Added: " + pageModel.getPage()); } } touchedForDownload = "Volumes"; executeDownloadTask(notDownloadedChapters, true); return true; default: return super.onOptionsItemSelected(item); } } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) menuInfo; MenuInflater inflater = getActivity().getMenuInflater(); int type = ExpandableListView.getPackedPositionType(info.packedPosition); if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) { inflater.inflate(R.menu.context_menu_novel_details_volume, menu); } else if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) { inflater.inflate(R.menu.context_menu_novel_details_chapter, menu); } } @Override public boolean onContextItemSelected(android.view.MenuItem item) { if (!(item.getMenuInfo() instanceof ExpandableListView.ExpandableListContextMenuInfo)) return super.onContextItemSelected(item); Log.d(TAG, "Context menu called"); ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) item.getMenuInfo(); // unpacking int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition); int childPosition = ExpandableListView.getPackedPositionChild(info.packedPosition); PageModel chapter; switch (item.getItemId()) { // Volume cases case R.id.download_volume: /* * Implement code to download this volume */ if(novelCol != null) { BookModel book = novelCol.getBookCollections().get(groupPosition); // get the chapter which not downloaded yet ArrayList<PageModel> downloadingChapters = new ArrayList<PageModel>(); for (PageModel temp : book.getChapterCollection()) { if (!temp.isExternal()) { if (temp.isDownloaded()) { if (dao.isContentUpdated(temp)) { downloadingChapters.add(temp); } } else { downloadingChapters.add(temp); } } } touchedForDownload = book.getTitle(); executeDownloadTask(downloadingChapters, false); } return true; case R.id.clear_volume: /* * Implement code to clear this volume cache */ BookModel bookClear = novelCol.getBookCollections().get(groupPosition); Toast.makeText(getActivity(), String.format(getResources().getString(R.string.toast_clear_volume), bookClear.getTitle()), Toast.LENGTH_SHORT).show(); dao.deleteBookCache(bookClear); for (PageModel page : bookClear.getChapterCollection()) { page.setDownloaded(false); } bookModelAdapter.notifyDataSetChanged(); return true; case R.id.mark_volume: /* * Implement code to mark entire volume as read */ Toast.makeText(getActivity(), getResources().getString(R.string.toast_mark_volume), Toast.LENGTH_SHORT).show(); BookModel book2 = novelCol.getBookCollections().get(groupPosition); for (PageModel page : book2.getChapterCollection()) { page.setFinishedRead(true); dao.updatePageModel(page); } bookModelAdapter.notifyDataSetChanged(); return true; case R.id.mark_volume2: /* * Implement code to mark entire volume as unread */ Toast.makeText(getActivity(), getResources().getString(R.string.toast_mark_volume2), Toast.LENGTH_SHORT).show(); BookModel unreadBooks = novelCol.getBookCollections().get(groupPosition); for (PageModel page : unreadBooks.getChapterCollection()) { page.setFinishedRead(false); dao.updatePageModel(page); } bookModelAdapter.notifyDataSetChanged(); return true; // Chapter cases case R.id.download_chapter: /* * Implement code to download this chapter */ chapter = bookModelAdapter.getChild(groupPosition, childPosition); String bookName = novelCol.getBookCollections().get(groupPosition).getTitle(); touchedForDownload = bookName + " " + chapter.getTitle(); downloadTask = new DownloadNovelContentTask(new PageModel[]{chapter}, touchedForDownload, this); downloadTask.execute(); return true; case R.id.clear_chapter: /* * Implement code to clear this chapter cache */ chapter = bookModelAdapter.getChild(groupPosition, childPosition); Toast.makeText(getActivity(), String.format(getResources().getString(R.string.toast_clear_chapter), chapter.getTitle()), Toast.LENGTH_SHORT).show(); dao.deleteChapterCache(chapter); chapter.setDownloaded(false); bookModelAdapter.notifyDataSetChanged(); return true; case R.id.mark_read: /* * Implement code to mark this chapter read >> change to toggle */ chapter = bookModelAdapter.getChild(groupPosition, childPosition); chapter.setFinishedRead(!chapter.isFinishedRead()); dao.updatePageModel(chapter); bookModelAdapter.notifyDataSetChanged(); Toast.makeText(getActivity(), getResources().getString(R.string.toast_toggle_read), Toast.LENGTH_SHORT).show(); return true; case R.id.delete_volume: /* * Implement code to delete this volume cache */ BookModel bookDel = novelCol.getBookCollections().get(groupPosition); Toast.makeText(getActivity(), getResources().getString(R.string.delete_this_volume, bookDel.getTitle()), Toast.LENGTH_SHORT).show(); dao.deleteBooks(bookDel); novelCol.getBookCollections().remove(groupPosition); bookModelAdapter.notifyDataSetChanged(); return true; case R.id.delete_chapter: /* * Implement code to delete this chapter cache */ chapter = bookModelAdapter.getChild(groupPosition, childPosition); Toast.makeText(getActivity(), getResources().getString(R.string.delete_this_chapter, chapter.getTitle()), Toast.LENGTH_SHORT).show(); dao.deleteNovelContent(chapter); dao.deletePage(chapter); novelCol.getBookCollections().get(groupPosition).getChapterCollection().remove(chapter); bookModelAdapter.notifyDataSetChanged(); return true; default: return super.onContextItemSelected(item); } } // region IExtendedCallbackNotifier @Override public boolean downloadListSetup(String id, String toastText, int type, boolean hasError) { boolean exists = false; if (!this.isAdded() || this.isDetached()) return false; if (page != null && !Util.isStringNullOrEmpty(page.getTitle())) { if (type == 0) { if (LNReaderApplication.getInstance().isDownloadExists(id)) { exists = true; Toast.makeText(getActivity(), getResources().getString(R.string.toast_download_on_queue), Toast.LENGTH_SHORT).show(); } else { String name = page.getTitle() + " " + touchedForDownload; Toast.makeText(getActivity(), getResources().getString(R.string.toast_downloading, name), Toast.LENGTH_SHORT).show(); LNReaderApplication.getInstance().addDownload(id, name); } } else if (type == 1) { Toast.makeText(getActivity(), "" + toastText, Toast.LENGTH_SHORT).show(); } else if (type == 2) { String downloadDescription = LNReaderApplication.getInstance().getDownloadName(id); if (downloadDescription != null) { String message = getResources().getString(R.string.toast_download_finish, page.getTitle(), downloadDescription); if (hasError) message = getResources().getString(R.string.toast_download_finish_with_error, page.getTitle(), downloadDescription); Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show(); } LNReaderApplication.getInstance().removeDownload(id); } } return exists; } @Override public void onProgressCallback(ICallbackEventData message) { toggleProgressBar(true); loadingText.setText(message.getMessage()); if (message.getPercentage() > 0) { LNReaderApplication.getInstance().updateDownload(message.getSource(), message.getPercentage(), message.getMessage()); if (loadingBar != null && loadingBar.getVisibility() == View.VISIBLE) { loadingBar.setIndeterminate(false); loadingBar.setMax(100); loadingBar.setProgress(message.getPercentage()); loadingBar.setProgress(0); loadingBar.setProgress(message.getPercentage()); loadingBar.setMax(100); } } else { loadingBar.setIndeterminate(true); } } @Override public void onCompleteCallback(ICallbackEventData message, AsyncTaskResult<?> result) { if (!isAdded()) return; Exception e = result.getError(); if (e == null) { // from DownloadNovelContentTask if (result.getResultType() == NovelContentModel[].class) { NovelContentModel[] content = (NovelContentModel[]) result.getResult(); if (content != null) { for (BookModel book : novelCol.getBookCollections()) { for (PageModel temp : book.getChapterCollection()) { for (int i = 0; i < content.length; ++i) { if (temp.getPage().equalsIgnoreCase(content[i].getPage())) { Log.d(TAG, "Page: " + content[i].getPage()); temp.setDownloaded(true); } } } } bookModelAdapter.notifyDataSetChanged(); } } // from LoadNovelDetailsTask else if (result.getResultType() == NovelCollectionModel.class) { novelCol = (NovelCollectionModel) result.getResult(); // now add the volume and chapter list. try { // Prepare header if (getArguments().getBoolean("show_list_child")) { page = novelCol.getPageModel(); LayoutInflater layoutInflater = getActivity().getLayoutInflater(); View synopsis = layoutInflater.inflate(R.layout.fragment_display_synopsis, null); TextView textViewTitle = (TextView) synopsis.findViewById(R.id.title); TextView textViewSynopsis = (TextView) synopsis.findViewById(R.id.synopsis); TextView textViewCategories = (TextView) synopsis.findViewById(R.id.categories); textViewTitle.setTextSize(20); textViewSynopsis.setTextSize(16); String title = page.getTitle(); if (page.isTeaser()) { title += " (Teaser Project)"; } if (page.isStalled()) { title += "\nStatus: Project Stalled"; } if (page.isAbandoned()) { title += "\nStatus: Project Abandoned"; } if (page.isPending()) { title += "\nStatus: Project Pending Authorization"; } getActivity().setTitle(page.getTitle()); textViewTitle.setText(title); textViewSynopsis.setText(novelCol.getSynopsis()); String tempCatList = Util.join(novelCol.getPageModel().getCategories(), ", "); tempCatList = tempCatList.replace("Category:", ""); textViewCategories.setText(tempCatList); CheckBox isWatched = (CheckBox) synopsis.findViewById(R.id.isWatched); isWatched.setChecked(page.isWatched()); isWatched.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { Toast.makeText(getActivity(), getResources().getString(R.string.toast_add_watch, page.getTitle()), Toast.LENGTH_SHORT).show(); } else { Toast.makeText(getActivity(), getResources().getString(R.string.toast_remove_watch, page.getTitle()), Toast.LENGTH_SHORT).show(); } // update the db! page.setWatched(isChecked); dao.updatePageModel(page); } }); setupCoverImage(synopsis); // update the header ScrollView v = (ScrollView) expandList.findViewById(R.id.novel_synopsis_screen); if (v != null) { v.removeAllViews(); v.addView(synopsis); } else expandList.addHeaderView(synopsis); } bookModelAdapter = new BookModelAdapter(getActivity(), novelCol.getBookCollections()); expandList.setAdapter(bookModelAdapter); } catch (Exception e2) { Log.e(TAG, "Error when setting up chapter list: " + e2.getMessage(), e2); Toast.makeText(getActivity(), getResources().getString(R.string.error_setting_chapter_list, e2.getMessage()), Toast.LENGTH_SHORT).show(); } } } else { String msg = e.getClass().toString(); if (e.getMessage() != null) msg += ": " + e.getMessage(); Log.e(TAG, msg, e); Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT).show(); } toggleProgressBar(false); } @SuppressLint("NewApi") private void setupCoverImage(View synopsis) { // cover ImageView ImageViewCover = (ImageView) synopsis.findViewById(R.id.cover); if (novelCol.getCoverBitmap() == null) { // IN app test, is returning empty bitmap Toast.makeText(getActivity(), getResources().getString(R.string.toast_err_bitmap_empty, novelCol.getCover()), Toast.LENGTH_LONG).show(); } else { ImageViewCover.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { handleCoverClick(novelCol.getCoverUrl()); } }); if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) && UIHelper.getStrechCoverPreference(getActivity())) { Drawable coverDrawable = new BitmapDrawable(getResources(), novelCol.getCoverBitmap()); int coverHeight = novelCol.getCoverBitmap().getHeight(); int coverWidth = novelCol.getCoverBitmap().getWidth(); double screenWidth = this.getView().getWidth() * 0.9; //UIHelper.getScreenWidth(getActivity()) * 0.9; double ratio = screenWidth / coverWidth; int finalHeight = (int) (coverHeight * ratio); ImageViewCover.setBackground(coverDrawable); ImageViewCover.getLayoutParams().height = finalHeight; ImageViewCover.getLayoutParams().width = (int) screenWidth; } else { ImageViewCover.setImageBitmap(novelCol.getCoverBitmap()); //ImageViewCover.getLayoutParams().height = novelCol.getCoverBitmap().getHeight(); //disable to avoid padding ImageViewCover.getLayoutParams().width = novelCol.getCoverBitmap().getWidth(); } } } // endregion // region private method private void handleCoverClick(URL coverUrl) { String bigCoverUrl = CommonParser.getImageFilePageFromImageUrl(coverUrl.toString()); Intent intent = new Intent(getActivity(), DisplayImageActivity.class); intent.putExtra(Constants.EXTRA_IMAGE_URL, bigCoverUrl); intent.putExtra(Constants.EXTRA_PAGE, this.page.getPage()); startActivity(intent); } private void toggleProgressBar(boolean show) { if (show) { loadingText.setText("Loading List, please wait..."); loadingText.setVisibility(TextView.VISIBLE); loadingBar.setVisibility(ProgressBar.VISIBLE); expandList.setVisibility(ListView.GONE); } else { loadingText.setVisibility(TextView.GONE); loadingBar.setVisibility(ProgressBar.GONE); expandList.setVisibility(ListView.VISIBLE); } } @SuppressLint("NewApi") private void executeTask(PageModel pageModel, boolean willRefresh) { String key = TAG + ":LoadNovelDetailsTask:" + pageModel.getPage(); task = new LoadNovelDetailsTask(pageModel, willRefresh, this, key); boolean isAdded = LNReaderApplication.getInstance().addTask(key, task); if (isAdded) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); else task.execute(); } else { Log.i(TAG, "Continue execute task: " + key); LoadNovelDetailsTask tempTask = (LoadNovelDetailsTask) LNReaderApplication.getInstance().getTask(key); if (tempTask != null) { task = tempTask; task.owner = this; } toggleProgressBar(true); } } @SuppressLint("NewApi") private void executeDownloadTask(ArrayList<PageModel> chapters, boolean isAll) { if (page != null) { String key = TAG + ":DownloadChapters:" + page.getPage(); if (isAll) { key = TAG + ":DownloadChaptersAll:" + page.getPage(); } downloadTask = new DownloadNovelContentTask(chapters.toArray(new PageModel[chapters.size()]), key, this); boolean isAdded = LNReaderApplication.getInstance().addTask(key, task); if (isAdded) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) downloadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); else downloadTask.execute(); } else { Log.i(TAG, "Continue download task: " + key); DownloadNovelContentTask tempTask = (DownloadNovelContentTask) LNReaderApplication.getInstance().getTask(key); if (tempTask != null) { downloadTask = tempTask; downloadTask.owner = this; } } } } private void loadChapter(PageModel chapter) { boolean useInternalWebView = PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean(Constants.PREF_USE_INTERNAL_WEBVIEW, false); if (chapter.isExternal() && !useInternalWebView) { try { Uri url = Uri.parse(chapter.getPage()); Intent browserIntent = new Intent(Intent.ACTION_VIEW, url); startActivity(browserIntent); } catch (Exception ex) { String message = getResources().getString(R.string.error_parsing_url, chapter.getPage()); Log.e(TAG, message, ex); Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show(); } } else { if (chapter.isExternal() || chapter.isDownloaded() || !UIHelper.getDownloadTouchPreference(getActivity())) { Intent intent = new Intent(getActivity(), DisplayLightNovelContentActivity.class); intent.putExtra(Constants.EXTRA_PAGE, chapter.getPage()); startActivity(intent); } else { downloadTask = new DownloadNovelContentTask(new PageModel[]{chapter}, TAG + ":load_chapter:" + chapter.getPage(), DisplayLightNovelDetailsFragment.this); downloadTask.execute(); } } } // endregion }