package com.erakk.lnreader.UI.fragment;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.SearchView;
import android.util.Log;
import android.view.ContextMenu;
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.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.erakk.lnreader.AlternativeLanguageInfo;
import com.erakk.lnreader.Constants;
import com.erakk.lnreader.LNReaderApplication;
import com.erakk.lnreader.R;
import com.erakk.lnreader.UIHelper;
import com.erakk.lnreader.adapter.PageModelAdapter;
import com.erakk.lnreader.callback.CallbackEventData;
import com.erakk.lnreader.callback.DownloadCallbackEventData;
import com.erakk.lnreader.callback.ICallbackEventData;
import com.erakk.lnreader.callback.IExtendedCallbackNotifier;
import com.erakk.lnreader.dao.NovelsDao;
import com.erakk.lnreader.model.NovelCollectionModel;
import com.erakk.lnreader.model.PageModel;
import com.erakk.lnreader.task.AddNovelTask;
import com.erakk.lnreader.task.AsyncTaskResult;
import com.erakk.lnreader.task.DownloadNovelDetailsTask;
import com.erakk.lnreader.task.LoadAlternativeTask;
import com.erakk.lnreader.task.LoadNovelsTask;
import org.jsoup.HttpStatusException;
import java.util.ArrayList;
/*
* Author: Nandaka
* Copy from: NovelsActivity.java
*/
public class DisplayLightNovelListFragment extends ListFragment implements IExtendedCallbackNotifier<AsyncTaskResult<?>>, INovelListHelper {
private static final String TAG = DisplayLightNovelListFragment.class.toString();
private final ArrayList<PageModel> listItems = new ArrayList<PageModel>();
private PageModelAdapter adapter;
private LoadNovelsTask task = null;
private LoadAlternativeTask altTask = null;
private DownloadNovelDetailsTask downloadTask = null;
private AddNovelTask addTask = null;
private boolean onlyWatched = false;
private String touchedForDownload;
private String mode;
private String lang;
private TextView loadingText;
private ProgressBar loadingBar;
private IFragmentListener mFragListener;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mFragListener = (IFragmentListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement FragListener");
}
mode = getArguments().getString(Constants.EXTRA_NOVEL_LIST_MODE);
if(mode == null) mode = Constants.EXTRA_NOVEL_LIST_MODE_MAIN;
onlyWatched = getArguments().getBoolean(Constants.EXTRA_ONLY_WATCHED, false);
lang = getArguments().getString(Constants.EXTRA_NOVEL_LANG);
Log.i(TAG, "IsWatched: " + onlyWatched + " Mode: " + mode + " lang: " + lang);
String page = getArguments().getString(Constants.EXTRA_PAGE);
String pageTitleHint = getArguments().getString(Constants.EXTRA_TITLE);
if (page != null)
loadNovel(page, pageTitleHint);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_display_light_novel_list, container, false);
if (onlyWatched) {
getActivity().setTitle("Watched Novels");
} else if (lang != null) {
getActivity().setTitle("Alt. Novels");
} else {
getActivity().setTitle("Light Novels");
}
loadingText = (TextView) view.findViewById(R.id.emptyList);
loadingBar = (ProgressBar) getActivity().findViewById(R.id.empttListProgress);
return view;
}
@Override
public void onStart() {
super.onStart();
/************************************************
* These lines of code require the ListView to already be created before
* they are used, hence, put in the onStart() method
****************************************************/
registerForContextMenu(getListView());
// Encapsulated in updateContent
updateContent(false, onlyWatched);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_display_novel_watched, menu);
MenuItem searchItem = menu.findItem(R.id.search_item);
if(searchItem != null) {
SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
if (searchView != null) {
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
Log.d("SEARCH", "Search: + " + query);
performSearch(query);
return false;
}
@Override
public boolean onQueryTextChange(String query) {
performSearch(query);
return false;
}
});
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
@Override
public boolean onClose() {
performSearch(null);
return false;
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
searchView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
}
@Override
public void onViewDetachedFromWindow(View v) {
performSearch(null);
}
});
}
}
}
}
private void performSearch(String query) {
if(adapter != null) {
adapter.filterData(query);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_download_all_info:
this.downloadAllNovelInfo();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
// Get the item that was clicked
PageModel o = adapter.getItem(position);
String novel = o.toString();
// Create a bundle containing information about the novel that is clicked
Bundle bundle = new Bundle();
bundle.putString(Constants.EXTRA_NOVEL, novel);
bundle.putString(Constants.EXTRA_PAGE, o.getPage());
bundle.putString(Constants.EXTRA_TITLE, o.getTitle());
bundle.putBoolean(Constants.EXTRA_ONLY_WATCHED, onlyWatched);
mFragListener.changeNextFragment(bundle);
Log.d(TAG, o.getPage() + " (" + o.getTitle() + ")");
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.context_menu_novel_item, menu);
}
@Override
public boolean onContextItemSelected(android.view.MenuItem item) {
if (!(item.getMenuInfo() instanceof AdapterView.AdapterContextMenuInfo))
return super.onContextItemSelected(item);
Log.d(TAG, "Context menu called");
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()) {
case R.id.add_to_watch:
/*
* Implement code to toggle watch of this novel
*/
if (info.position > -1) {
PageModel novel = listItems.get(info.position);
if (novel.isWatched()) {
novel.setWatched(false);
Toast.makeText(getActivity(), "Removed from watch list: " + novel.getTitle(), Toast.LENGTH_SHORT).show();
} else {
novel.setWatched(true);
Toast.makeText(getActivity(), "Added to watch list: " + novel.getTitle(), Toast.LENGTH_SHORT).show();
}
NovelsDao.getInstance().updatePageModel(novel);
adapter.notifyDataSetChanged();
}
return true;
case R.id.download_novel:
/*
* Implement code to download novel synopsis
*/
if (info.position > -1) {
PageModel novel = listItems.get(info.position);
ArrayList<PageModel> novels = new ArrayList<PageModel>();
novels.add(novel);
touchedForDownload = novel.getTitle() + "'s information";
executeDownloadTask(novels);
}
return true;
case R.id.delete_novel:
if (info.position > -1) {
toggleProgressBar(true);
PageModel novel = listItems.get(info.position);
int result = NovelsDao.getInstance().deleteNovel(novel);
if (result > 0) {
listItems.remove(novel);
adapter.notifyDataSetChanged();
}
toggleProgressBar(false);
}
return true;
default:
return super.onContextItemSelected(item);
}
}
// region private methods
private void updateContent(boolean isRefresh, boolean onlyWatched) {
// use the cached items.
if (!isRefresh && listItems != null && listItems.size() > 0)
return;
try {
// Check size
int resourceId = R.layout.item_novel;
if (UIHelper.isSmallScreen(getActivity())) {
resourceId = R.layout.item_novel_small;
}
if (adapter != null) {
adapter.setResourceId(resourceId);
} else {
adapter = new PageModelAdapter(getActivity(), resourceId, listItems);
}
boolean alphOrder = UIHelper.isAlphabeticalOrder(getActivity());
if (lang == null)
executeTask(isRefresh, onlyWatched, alphOrder);
else {
executeAltTask(isRefresh, alphOrder, lang);
}
setListAdapter(adapter);
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
Toast.makeText(getActivity(), "Error when updating: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
@SuppressLint("NewApi")
private void executeTask(boolean isRefresh, boolean onlyWatched, boolean alphOrder) {
task = new LoadNovelsTask(this, isRefresh, onlyWatched, alphOrder, mode);
String key = null;
if (mode.equalsIgnoreCase(Constants.EXTRA_NOVEL_LIST_MODE_MAIN)) {
key = TAG + ":LoadNovelsTask:" + Constants.ROOT_NOVEL_ENGLISH;
} else if (mode.equalsIgnoreCase(Constants.EXTRA_NOVEL_LIST_MODE_TEASER)) {
key = TAG + ":LoadNovelsTask:" + Constants.ROOT_TEASER;
} else if (mode.equalsIgnoreCase(Constants.EXTRA_NOVEL_LIST_MODE_ORIGINAL)) {
key = TAG + ":LoadNovelsTask:" + Constants.ROOT_ORIGINAL;
} else if (mode.equalsIgnoreCase(Constants.EXTRA_NOVEL_LIST_MODE_WEB)) {
key = TAG + ":LoadNovelsTask:" + Constants.ROOT_WEB;
}
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);
LoadNovelsTask tempTask = (LoadNovelsTask) LNReaderApplication.getInstance().getTask(key);
if (tempTask != null) {
task = tempTask;
task.owner = this;
}
}
toggleProgressBar(true);
}
private void executeAltTask(boolean isRefresh, boolean alphOrder, String lang) {
altTask = new LoadAlternativeTask(this, isRefresh, alphOrder, lang);
String key = null;
if (lang != null)
key = TAG + ":LoadAlternativeTask:" + AlternativeLanguageInfo.getAlternativeLanguageInfo().get(lang).getCategoryInfo();
boolean isAdded = LNReaderApplication.getInstance().addTask(key, altTask);
if (isAdded) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
altTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
altTask.execute();
} else {
Log.i(TAG, "Continue execute task: " + key);
LoadAlternativeTask tempTask = (LoadAlternativeTask) LNReaderApplication.getInstance().getTask(key);
if (tempTask != null) {
altTask = tempTask;
altTask.owner = this;
}
}
toggleProgressBar(true);
}
@SuppressLint("NewApi")
private void executeDownloadTask(ArrayList<PageModel> novels) {
downloadTask = new DownloadNovelDetailsTask(this);
if (novels == null || novels.size() == 0)
return;
String key = DisplayLightNovelDetailsFragment.TAG + ":" + novels.get(0).getPage();
if (novels.size() > 1) {
if (mode.equalsIgnoreCase(Constants.EXTRA_NOVEL_LIST_MODE_MAIN)) {
key = DisplayLightNovelDetailsFragment.TAG + ":All_Novels";
} else if (mode.equalsIgnoreCase(Constants.EXTRA_NOVEL_LIST_MODE_TEASER)) {
key = DisplayLightNovelDetailsFragment.TAG + ":All_Teasers";
} else if (mode.equalsIgnoreCase(Constants.EXTRA_NOVEL_LIST_MODE_ORIGINAL)) {
key = DisplayLightNovelDetailsFragment.TAG + ":All_Original";
}
}
boolean isAdded = LNReaderApplication.getInstance().addTask(key, downloadTask);
if (isAdded) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
downloadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, novels.toArray(new PageModel[novels.size()]));
else
downloadTask.execute(novels.toArray(new PageModel[novels.size()]));
} else {
Log.i(TAG, "Continue download task: " + key);
DownloadNovelDetailsTask tempTask = (DownloadNovelDetailsTask) LNReaderApplication.getInstance().getTask(key);
if (tempTask != null) {
downloadTask = tempTask;
downloadTask.owner = this;
}
toggleProgressBar(true);
}
}
@SuppressLint("NewApi")
private void executeAddTask(PageModel novel) {
String key = DisplayLightNovelDetailsFragment.TAG + ":Add:" + novel.getPage();
addTask = new AddNovelTask(this, key);
boolean isAdded = LNReaderApplication.getInstance().addTask(key, addTask);
if (isAdded) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
addTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new PageModel[]{novel});
else
addTask.execute(new PageModel[]{novel});
} else {
Log.i(TAG, "Continue Add task: " + key);
AddNovelTask tempTask = (AddNovelTask) LNReaderApplication.getInstance().getTask(key);
if (tempTask != null) {
addTask = tempTask;
addTask.owner = this;
}
}
toggleProgressBar(true);
}
private void loadNovel(String page, String novelTitleHint) {
Bundle bundle = new Bundle();
bundle.putString(Constants.EXTRA_PAGE, page);
bundle.putString(Constants.EXTRA_TITLE, novelTitleHint);
mFragListener.changeNextFragment(bundle);
}
@Override
public void refreshList() {
boolean onlyWatched = getActivity().getIntent().getBooleanExtra(Constants.EXTRA_ONLY_WATCHED, false);
updateContent(true, onlyWatched);
Toast.makeText(getActivity(), "Refreshing " + mode + " Novel...", Toast.LENGTH_SHORT).show();
}
@Override
public void downloadAllNovelInfo() {
if (onlyWatched) {
touchedForDownload = "Watched Light Novels information";
} else if (mode == null || mode.equalsIgnoreCase(Constants.EXTRA_NOVEL_LIST_MODE_MAIN)) {
touchedForDownload = "All Main Light Novels information";
} else if (mode.equalsIgnoreCase(Constants.EXTRA_NOVEL_LIST_MODE_TEASER)) {
touchedForDownload = "All Teaser Light Novels information";
} else if (mode.equalsIgnoreCase(Constants.EXTRA_NOVEL_LIST_MODE_ORIGINAL)) {
touchedForDownload = "All Original Light Novels information";
}
executeDownloadTask(listItems);
}
@Override
public void manualAdd() {
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
alert.setTitle(getString(R.string.add_novel_main, mode));
LayoutInflater factory = LayoutInflater.from(getActivity());
View inputView = factory.inflate(R.layout.dialog_add_new_novel, null);
final EditText inputName = (EditText) inputView.findViewById(R.id.page);
final EditText inputTitle = (EditText) inputView.findViewById(R.id.title);
alert.setView(inputView);
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
if (whichButton == DialogInterface.BUTTON_POSITIVE) {
handleOK(inputName, inputTitle);
}
}
});
alert.setNegativeButton("Cancel", null);
alert.show();
}
private void handleOK(EditText input, EditText inputTitle) {
String novel = input.getText().toString();
String title = inputTitle.getText().toString();
if (novel != null && novel.length() > 0 && inputTitle != null && inputTitle.length() > 0) {
PageModel temp = new PageModel();
temp.setPage(novel);
temp.setTitle(title);
temp.setType(PageModel.TYPE_NOVEL);
temp.setParent(Constants.ROOT_NOVEL_ENGLISH);
if (mode.equalsIgnoreCase(Constants.EXTRA_NOVEL_LIST_MODE_MAIN)) {
temp.setParent(Constants.ROOT_NOVEL_ENGLISH);
} else if (mode.equalsIgnoreCase(Constants.EXTRA_NOVEL_LIST_MODE_TEASER)) {
temp.setParent(Constants.ROOT_TEASER);
temp.setStatus(Constants.STATUS_TEASER);
} else if (mode.equalsIgnoreCase(Constants.EXTRA_NOVEL_LIST_MODE_ORIGINAL)) {
temp.setParent(Constants.ROOT_ORIGINAL);
temp.setStatus(Constants.STATUS_ORIGINAL);
}
executeAddTask(temp);
} else {
Toast.makeText(getActivity(), "Empty Input", Toast.LENGTH_LONG).show();
}
}
private void toggleProgressBar(boolean show) {
View root = getView();
if (root != null) {
ListView listView = getListView();
if (listView == null || loadingText == null || loadingBar == null)
return;
if (show) {
loadingText.setText("Loading List, please wait...");
loadingText.setVisibility(TextView.VISIBLE);
loadingBar.setVisibility(ProgressBar.VISIBLE);
listView.setVisibility(ListView.GONE);
} else {
loadingText.setVisibility(TextView.GONE);
loadingBar.setVisibility(ProgressBar.GONE);
listView.setVisibility(ListView.VISIBLE);
}
}
}
// endregion
// region IExtendedCallbackNotifier<AsyncTaskResult<?>> implementation
@Override
public void onCompleteCallback(ICallbackEventData message, AsyncTaskResult<?> result) {
if (!isAdded())
return;
Exception e = result.getError();
if (e == null) {
Class t = result.getResultType();
// from LoadNovelsTask
if (t == PageModel[].class) {
PageModel[] list = (PageModel[]) result.getResult();
Log.d(TAG, "LoadNovelsTask result ok");
if (list != null && list.length > 0) {
adapter.clear();
adapter.addAll(list);
toggleProgressBar(false);
// Show message if watch list is empty
if (list.length == 0 && onlyWatched) {
Log.d(TAG, "WatchList result set message empty");
if (loadingText != null) {
loadingText.setVisibility(TextView.VISIBLE);
loadingText.setText("Watch List is empty.");
}
}
} else {
toggleProgressBar(false);
if (loadingText != null) {
loadingText.setVisibility(TextView.VISIBLE);
loadingText.setText(getResources().getString(R.string.list_empty));
}
Log.w(TAG, "Empty ArrayList!");
}
}
// from DownloadNovelDetailsTask
else if (t == NovelCollectionModel[].class) {
onProgressCallback(new CallbackEventData("Download complete.", "DownloadNovelDetailsTask"));
NovelCollectionModel[] list = (NovelCollectionModel[]) result.getResult();
for (NovelCollectionModel novelCol : list) {
try {
PageModel page = novelCol.getPageModel();
boolean found = false;
for (PageModel temp : adapter.data) {
if (temp.getPage().equalsIgnoreCase(page.getPage())) {
found = true;
break;
}
}
if (!found) {
adapter.data.add(page);
}
} catch (Exception e1) {
Log.e(TAG, e1.getClass().toString() + ": " + e1.getMessage(), e1);
}
}
adapter.notifyDataSetChanged();
toggleProgressBar(false);
} else {
Log.e(TAG, "Unknown ResultType: " + t.getName());
}
} else {
String msg = e.getMessage();
Log.e(TAG, e.getClass().toString() + ": " + message, e);
if (e.getClass() == HttpStatusException.class) {
HttpStatusException hes = (HttpStatusException) e;
msg += ". Status=" + hes.getStatusCode();
}
Toast.makeText(getActivity(), e.getClass().toString() + ": " + msg, Toast.LENGTH_LONG).show();
}
toggleProgressBar(false);
}
@Override
public void onProgressCallback(ICallbackEventData message) {
if (loadingText != null && loadingText.getVisibility() == TextView.VISIBLE)
loadingText.setText(message.getMessage());
if (message instanceof DownloadCallbackEventData) {
DownloadCallbackEventData downloadData = (DownloadCallbackEventData) message;
LNReaderApplication.getInstance().updateDownload(message.getSource(), downloadData.getPercentage(), message.getMessage());
if (loadingBar != null && loadingBar.getVisibility() == View.VISIBLE) {
loadingBar.setIndeterminate(false);
loadingBar.setMax(100);
loadingBar.setProgress(downloadData.getPercentage());
loadingBar.setProgress(0);
loadingBar.setProgress(downloadData.getPercentage());
loadingBar.setMax(100);
}
}
}
/**
* @param id task id
* @param toastText toast text
* @param type 0=Add Download 1=Show progress 2=Remove Download
* @param hasError has error?
* @return
*/
@Override
public boolean downloadListSetup(String id, String toastText, int type, boolean hasError) {
if (!this.isAdded() || this.isDetached())
return false;
boolean exists = false;
if (type == 0) {
if (LNReaderApplication.getInstance().isDownloadExists(id)) {
exists = true;
Toast.makeText(getActivity(), "Download already on queue.", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getActivity(), "Downloading " + touchedForDownload + ".", Toast.LENGTH_SHORT).show();
LNReaderApplication.getInstance().addDownload(id, touchedForDownload);
}
} else if (type == 1) {
Toast.makeText(getActivity(), toastText, Toast.LENGTH_SHORT).show();
} else if (type == 2) {
String name = LNReaderApplication.getInstance().getDownloadName(id);
if (name != null) {
String message = String.format("%s's download finished!", name);
if (hasError)
message = String.format("%s's download finished with error(s)!", name);
Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
LNReaderApplication.getInstance().removeDownload(id);
}
}
return exists;
}
// endregion
}