/*
Copyright (C) 2012 Haowen Ning
This program 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 2
of the License, or (at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.liberty.android.fantastischmemo.downloader.common;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import org.liberty.android.fantastischmemo.R;
import org.liberty.android.fantastischmemo.common.BaseFragment;
import org.liberty.android.fantastischmemo.utils.AMGUIUtility;
import org.liberty.android.fantastischmemo.utils.RecentListUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import javax.inject.Inject;
/**
* The abstract class for an acitvity that displays a list of card sets
* to download.
*/
public abstract class AbstractDownloaderFragment extends BaseFragment {
private static final String TAG = AbstractDownloaderFragment.class.getSimpleName();
private Activity mActivity;
private ListView listView;
private DownloadListAdapter dlAdapter;
private View loadMoreFooter;
private View loadingProgressFooter;
@Inject RecentListUtil recentListUtil;
/**
* Retrieve the DownloadItem for the first time.
* @return a list of download item.
* @throws Exception exceptions
*/
abstract protected List<DownloadItem> initialRetrieve() throws Exception;
/**
* Retrieve more DownloadItem
* @return a list of download item.
* @throws Exception exceptions
*/
abstract protected List<DownloadItem> loadMore() throws Exception;
/**
* Return if there are more cards to load.
*
* This is called after any loading
*
* @return true if there are more download item to retrieve
*/
abstract protected boolean hasMore();
/**
* Retrieve the data when the user has clicked a category
*/
abstract protected List<DownloadItem> openCategory(DownloadItem di);
/**
* Go back to the previous list
*/
abstract protected List<DownloadItem> goBack();
/**
* Download the database based on the info
*/
abstract protected String fetchDatabase(DownloadItem di) throws Exception;
/**
* Get specific item from the Adapter or else
* @param position the posotion of the item in the list
* @return the downloaditem at that position
*/
protected DownloadItem getDownloadItem(int position) {
return dlAdapter.getItem(position);
};
/**
* Get the count of the download items
* @return the download item count.
*/
protected int getDownloadItemCount() {
return dlAdapter.getCount();
}
@Override
public void onAttach(Context activity) {
super.onAttach(activity);
mActivity = (Activity) activity;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fragmentComponents().inject(this);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
// The file browser's is reused here because they are similar
View v = inflater.inflate(R.layout.file_list, container, false);
listView = (ListView)v.findViewById(R.id.file_list);
// Initial two footers that is displayed in the bottom of the list
loadMoreFooter = ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.list_load_more_footer, null, false);
loadingProgressFooter = ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.list_loading_progress_footer, null, false);
loadMoreFooter.setOnClickListener(loadMoreOnClickListener);
// Must nullify the onclick listener on loadingProgressFooter
// Or it will be treated a list item and cause index out of bount exception.
loadingProgressFooter.setOnClickListener(null);
dlAdapter = new DownloadListAdapter(mActivity, R.layout.filebrowser_item);
// This is for android 2.3 compatibility. The addFooterView needs to be called
// before setAdapter.
listView.addFooterView(loadMoreFooter);
listView.setAdapter(dlAdapter);
listView.removeFooterView(loadMoreFooter);
refreshList();
return v;
}
/**
* Clear the list and re-run initialRetrieve
*/
public void refreshList() {
dlAdapter.clear();
RetrieveTask task = new RetrieveTask();
task.execute(new Callable<List<DownloadItem>>() {
@Override
public List<DownloadItem> call() throws Exception {
return initialRetrieve();
}
});
}
private class RetrieveTask extends AsyncTask<Callable<List<DownloadItem>>, Void, Exception> {
private ProgressDialog progressDialog;
private List<DownloadItem> downloadItems = new ArrayList<>();
@Override
public void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(mActivity);
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.setTitle(getString(R.string.loading_please_wait));
progressDialog.setMessage(getString(R.string.loading_connect_net));
progressDialog.setCancelable(false);
progressDialog.show();
listView.addFooterView(loadingProgressFooter);
}
@Override
public Exception doInBackground(Callable<List<DownloadItem>>... tasks) {
try {
for (Callable<List<DownloadItem>> task : tasks) {
downloadItems.addAll(task.call());
}
} catch (Exception e) {
return e;
}
return null;
}
@Override
public void onPostExecute(Exception e){
listView.removeFooterView(loadingProgressFooter);
progressDialog.dismiss();
if (e != null) {
AMGUIUtility.displayError(mActivity, getString(R.string.downloader_connection_error), getString(R.string.downloader_connection_error_message), e);
return;
}
dlAdapter.clear();
dlAdapter.addList(downloadItems);
if (hasMore()) {
listView.addFooterView(loadMoreFooter);
}
}
}
private class LoadMoreTask extends AsyncTask<Void, Void, Exception> {
private List<DownloadItem> downloadItems;
@Override
public void onPreExecute() {
super.onPreExecute();
listView.removeFooterView(loadMoreFooter);
listView.addFooterView(loadingProgressFooter);
}
@Override
public Exception doInBackground(Void... nothing) {
try {
downloadItems = loadMore();
} catch (Exception e) {
return e;
}
return null;
}
@Override
public void onPostExecute(Exception e){
// Always remove the progress footer
listView.removeFooterView(loadingProgressFooter);
if (e != null) {
AMGUIUtility.displayException(mActivity, getString(R.string.downloader_connection_error), getString(R.string.downloader_connection_error_message), e);
return;
}
dlAdapter.addList(downloadItems);
// Add the "loadMoreFooter" only if we successfully retrieve the list
if (hasMore()) {
listView.addFooterView(loadMoreFooter);
}
}
}
protected void showFetchDatabaseDialog(final DownloadItem item) {
View alertView = View.inflate(mActivity, R.layout.link_alert, null);
TextView textView = (TextView)alertView.findViewById(R.id.link_alert_message);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(Html.fromHtml(getString(R.string.downloader_download_alert_message) + item.getDescription()));
new AlertDialog.Builder(mActivity)
.setView(alertView)
.setTitle(getString(R.string.downloader_download_alert) + item.getTitle())
.setPositiveButton(getString(R.string.yes_text), new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface arg0, int arg1){
startFetchDatabaseTask(item);
}
})
.setNegativeButton(getString(R.string.no_text), null)
.show();
}
protected void startFetchDatabaseTask(final DownloadItem item) {
FetchDatabaseTask task = new FetchDatabaseTask();
task.execute(item);
}
private class FetchDatabaseTask extends AsyncTask<DownloadItem, Void, Exception> {
private ProgressDialog progressDialog;
private DownloadItem item;
private String fetchedDbPath;
@Override
public void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(mActivity);
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.setTitle(getString(R.string.loading_please_wait));
progressDialog.setMessage(getString(R.string.loading_downloading));
progressDialog.setCancelable(false);
progressDialog.show();
}
@Override
public Exception doInBackground(DownloadItem... items) {
try {
item = items[0];
fetchedDbPath = fetchDatabase(item);
} catch (Exception e) {
Log.e(TAG, "Error fetch db lists", e);
return e;
}
return null;
}
@Override
public void onPostExecute(Exception e){
progressDialog.dismiss();
if (e != null) {
AMGUIUtility.displayException(mActivity, getString(R.string.error_text), getString(R.string.downloader_download_fail_message), e);
return;
} else {
new AlertDialog.Builder(mActivity)
.setTitle(R.string.downloader_download_success)
.setMessage(getString(R.string.downloader_download_success_message) + fetchedDbPath)
.setPositiveButton(R.string.ok_text, null)
.show();
recentListUtil.addToRecentList(fetchedDbPath);
}
}
}
private View.OnClickListener loadMoreOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
LoadMoreTask task = new LoadMoreTask();
task.execute();
}
};
/*
* Helper class to provide the info for each items
* that could be categories, databases and other
* special things
*/
protected class DownloadListAdapter extends ArrayAdapter<DownloadItem>{
public DownloadListAdapter(Context context, int textViewResourceId){
super(context, textViewResourceId);
}
public void addList(List<DownloadItem> list){
for(DownloadItem di : list){
add(di);
}
}
public ArrayList<DownloadItem> getList(){
ArrayList<DownloadItem> list = new ArrayList<DownloadItem>();
int count = getCount();
for(int i = 0; i < count; i++){
list.add(getItem(i));
}
return list;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent){
View v = convertView;
if (v == null){
LayoutInflater li = (LayoutInflater)mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
/* Reuse the filebrowser's resources */
v = li.inflate(R.layout.filebrowser_item, null);
}
DownloadItem item = getItem(position);
if (item != null){
TextView tv = (TextView)v.findViewById(R.id.file_name);
ImageView iv = (ImageView)v.findViewById(R.id.file_icon);
if (item.getType() == DownloadItem.ItemType.Category) {
iv.setImageResource(R.drawable.dir);
} else if (item.getType() == DownloadItem.ItemType.Back) {
iv.setImageResource(R.drawable.back);
} else if (item.getType() == DownloadItem.ItemType.Spreadsheet) {
iv.setImageResource(R.drawable.spreadsheet);
} else {
iv.setImageResource(R.drawable.database);
}
tv.setText(item.getTitle());
}
v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final DownloadItem di = getDownloadItem(position);
if(di == null){
Log.e(TAG, "NULL Download Item");
return;
}
if(di.getType() == DownloadItem.ItemType.Category){
RetrieveTask task = new RetrieveTask();
task.execute(new Callable<List<DownloadItem>>() {
@Override
public List<DownloadItem> call() throws Exception {
return openCategory(di);
}
});
} else if(di.getType() == DownloadItem.ItemType.Back){
RetrieveTask task = new RetrieveTask();
task.execute(new Callable<List<DownloadItem>>() {
@Override
public List<DownloadItem> call() throws Exception {
return goBack();
}
});
} else {
showFetchDatabaseDialog(di);
}
}
});
return v;
}
}
}