/*
Copyright (C) 2013 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.ui;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.text.Html;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.google.common.base.Strings;
import org.liberty.android.fantastischmemo.common.AnyMemoDBOpenHelper;
import org.liberty.android.fantastischmemo.common.AnyMemoDBOpenHelperManager;
import org.liberty.android.fantastischmemo.R;
import org.liberty.android.fantastischmemo.common.BaseFragment;
import org.liberty.android.fantastischmemo.dao.CardDao;
import org.liberty.android.fantastischmemo.dao.LearningDataDao;
import org.liberty.android.fantastischmemo.entity.Card;
import org.liberty.android.fantastischmemo.entity.LearningData;
import org.liberty.android.fantastischmemo.entity.Option;
import org.liberty.android.fantastischmemo.scheduler.Scheduler;
import org.liberty.android.fantastischmemo.utils.AMDateUtil;
import javax.inject.Inject;
/*
* Display the control bar in CardPlayerActivity. Handle the logic
* of controlling the CardPlayerService.
*/
public class GradeButtonsFragment extends BaseFragment {
private static final String TAG = GradeButtonsFragment.class.getSimpleName();
public static final String EXTRA_DBPATH = "dbpath";
private QACardActivity activity;
private AnyMemoDBOpenHelper dbOpenHelper;
private LinearLayout buttonView;
private Option option;
private Button[] gradeButtons = new Button[6];
private CardDao cardDao;
private LearningDataDao learningDataDao;
private OnCardChangedListener onCardChangedListener;
private Handler handler = new Handler();
@Inject Scheduler scheduler;
@Inject AMDateUtil amDateUtil;
// The default button titles from the string
private CharSequence[] defaultGradeButtonTitles = new CharSequence[6];
public GradeButtonsFragment() { }
public void setOnCardChangedListener(
OnCardChangedListener onCardChangedListener) {
this.onCardChangedListener = onCardChangedListener;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fragmentComponents().inject(this);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.activity = (QACardActivity) activity;
Bundle args = getArguments();
String dbPath = args.getString(EXTRA_DBPATH);
dbOpenHelper = AnyMemoDBOpenHelperManager.getHelper(activity, dbPath);
cardDao = dbOpenHelper.getCardDao();
learningDataDao = dbOpenHelper.getLearningDataDao();
option = appComponents().option();
}
@Override
public void onDetach() {
super.onDetach();
AnyMemoDBOpenHelperManager.releaseHelper(dbOpenHelper);
}
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
int gradeButtonResource;
switch (option.getButtonStyle()) {
case ANKI:
gradeButtonResource = R.layout.grade_buttons_anki;
break;
case MNEMOSYNE:
gradeButtonResource = R.layout.grade_buttons_mnemosyne;
break;
default:
gradeButtonResource = R.layout.grade_buttons_anymemo;
}
if (activity instanceof QuizActivity) {
gradeButtonResource = R.layout.grade_buttons_quiz;
}
buttonView = (LinearLayout) inflater.inflate(gradeButtonResource, null);
// Make sure touching all areas can reveal the card.
buttonView.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
activity.onClickAnswerView();
}
});
buttonView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
activity.onClickAnswerView();
return true ;
}
});
gradeButtons[0] = (Button)buttonView.findViewById(R.id.grade_button_0);
gradeButtons[1] = (Button)buttonView.findViewById(R.id.grade_button_1);
gradeButtons[2] = (Button)buttonView.findViewById(R.id.grade_button_2);
gradeButtons[3] = (Button)buttonView.findViewById(R.id.grade_button_3);
gradeButtons[4] = (Button)buttonView.findViewById(R.id.grade_button_4);
gradeButtons[5] = (Button)buttonView.findViewById(R.id.grade_button_5);
for (int i = 0; i < 6; i++) {
setButtonOnClickListener(gradeButtons[i], i);
setButtonOnLongClickListener(gradeButtons[i], i);
defaultGradeButtonTitles[i] = gradeButtons[i].getText();
gradeButtons[i].setText(Html.fromHtml("<b>" + gradeButtons[i].getText() + "</b>"));
}
return buttonView;
}
public void gradeCurrentCard(int grade) {
onGradeButtonClickListener.onGradeButtonClick(grade);
}
private void setButtonOnClickListener(final Button button, final int grade) {
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
onGradeButtonClickListener.onGradeButtonClick(grade);
}
});
}
private void setButtonOnLongClickListener(final Button button, final int grade) {
button.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View v) {
int[] helpText = {
R.string.memo_btn0_help_text,
R.string.memo_btn1_help_text,
R.string.memo_btn2_help_text,
R.string.memo_btn3_help_text,
R.string.memo_btn4_help_text,
R.string.memo_btn5_help_text
};
Toast.makeText(getActivity(), helpText[grade], Toast.LENGTH_LONG)
.show();
return true;
}
});
}
private OnGradeButtonClickListener onGradeButtonClickListener =
new OnGradeButtonClickListener() {
public void onGradeButtonClick(int grade) {
GradeTask gradeTask = new GradeTask();
gradeTask.execute(grade);
}
};
@SuppressWarnings("unused")
private void setButtonText(int grade, CharSequence title, CharSequence description) {
if (description != null && !Strings.isNullOrEmpty(description.toString())) {
gradeButtons[grade].setText(Html.fromHtml("<b>" + title + "</b>" + "<br />" + "<small>" + description + "</small>"));
} else {
gradeButtons[grade].setText(Html.fromHtml("<b>" + title + "</b>"));
}
}
private void setButtonDescription(int grade, CharSequence description) {
if (description != null && !Strings.isNullOrEmpty(description.toString())) {
gradeButtons[grade].setText(Html.fromHtml("<b>" + defaultGradeButtonTitles[grade] + "</b>" + "<br />" + "<small>" + description + "</small>"));
}
}
public static interface OnGradeButtonClickListener {
void onGradeButtonClick(int grade);
}
/*
* Set the visibility of the buttons view.
* The visibility is the same as View.GONE / VISIBLE / INVISIBLE.
*/
public void setVisibility(final int visibility) {
// This must be called throgh handler because it needs to
// wait until the init of the fragment done.
handler.post(new Runnable() {
public void run() {
buttonView.setVisibility(visibility);
setGradeButtonTitle();
}
});
}
/*
* Use AsyncTask to update the database and update the statistics
* information
*/
private class GradeTask extends AsyncTask<Integer, Void, Void> {
private Card prevCard;
private Card updatedCard;
@Override
public void onPreExecute() {
super.onPreExecute();
activity.setProgressBarIndeterminateVisibility(true);
}
@Override
public Void doInBackground(Integer... grades) {
assert grades.length == 1 : "Grade more than 1 time";
int grade = grades[0];
// Save current card as prev card for undo.
// This was saved to determine the stat info
// and the card id for undo
prevCard = activity.getCurrentCard();
// Save previous learning for Undo
// This part is ugly due to mutablity of ORMLite
updatedCard = cardDao.queryForId(activity.getCurrentCard().getId());
learningDataDao.refresh(updatedCard.getLearningData());
LearningData newLd = scheduler.schedule(prevCard.getLearningData(), grade, true);
// Need to clone the data due to ORMLite restriction on "update()" method.
updatedCard.getLearningData().cloneFromLearningData(newLd);
return null;
}
@Override
public void onPostExecute(Void result){
super.onPostExecute(result);
activity.setProgressBarIndeterminateVisibility(false);
Log.v(TAG, "Prev card: " + prevCard);
Log.v(TAG, "Updated card: " + updatedCard);
onCardChangedListener.onCardChanged(prevCard, updatedCard);
}
}
public static interface OnCardChangedListener {
void onCardChanged(Card prevCard, Card updatedCard);
}
private void setGradeButtonTitle() {
// Mnemosyne grade button style won't display the interval.
// QuizAcivity does not write to db so it does not make sense to display.
if (option.getButtonStyle() != Option.ButtonStyle.MNEMOSYNE && !(activity instanceof QuizActivity)) {
setButtonDescription(0, ""+ amDateUtil.convertDayIntervalToDisplayString(scheduler.schedule(activity.getCurrentCard().getLearningData(), 0, false).getInterval()));
setButtonDescription(1, ""+ amDateUtil.convertDayIntervalToDisplayString(scheduler.schedule(activity.getCurrentCard().getLearningData(), 1, false).getInterval()));
setButtonDescription(2, ""+ amDateUtil.convertDayIntervalToDisplayString(scheduler.schedule(activity.getCurrentCard().getLearningData(), 2, false).getInterval()));
setButtonDescription(3, ""+ amDateUtil.convertDayIntervalToDisplayString(scheduler.schedule(activity.getCurrentCard().getLearningData(), 3, false).getInterval()));
setButtonDescription(4, ""+ amDateUtil.convertDayIntervalToDisplayString(scheduler.schedule(activity.getCurrentCard().getLearningData(), 4, false).getInterval()));
setButtonDescription(5, ""+ amDateUtil.convertDayIntervalToDisplayString(scheduler.schedule(activity.getCurrentCard().getLearningData(), 5, false).getInterval()));
}
}
}