/*
* Copyright 2015 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.topeka.fragment;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.animation.FastOutLinearInInterpolator;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterViewAnimator;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.google.samples.apps.topeka.R;
import com.google.samples.apps.topeka.adapter.QuizAdapter;
import com.google.samples.apps.topeka.adapter.ScoreAdapter;
import com.google.samples.apps.topeka.helper.ApiLevelHelper;
import com.google.samples.apps.topeka.helper.PreferencesHelper;
import com.google.samples.apps.topeka.model.Category;
import com.google.samples.apps.topeka.model.Player;
import com.google.samples.apps.topeka.model.Theme;
import com.google.samples.apps.topeka.model.quiz.Quiz;
import com.google.samples.apps.topeka.persistence.TopekaDatabaseHelper;
import com.google.samples.apps.topeka.widget.AvatarView;
import com.google.samples.apps.topeka.widget.quiz.AbsQuizView;
import java.util.List;
/**
* Encapsulates Quiz solving and displays it to the user.
*/
public class QuizFragment extends android.support.v4.app.Fragment {
private static final String KEY_USER_INPUT = "USER_INPUT";
private TextView mProgressText;
private int mQuizSize;
private ProgressBar mProgressBar;
private Category mCategory;
private AdapterViewAnimator mQuizView;
private ScoreAdapter mScoreAdapter;
private QuizAdapter mQuizAdapter;
private SolvedStateListener mSolvedStateListener;
public static QuizFragment newInstance(String categoryId,
SolvedStateListener solvedStateListener) {
if (categoryId == null) {
throw new IllegalArgumentException("The category can not be null");
}
Bundle args = new Bundle();
args.putString(Category.TAG, categoryId);
QuizFragment fragment = new QuizFragment();
if (solvedStateListener != null) {
fragment.mSolvedStateListener = solvedStateListener;
}
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
String categoryId = getArguments().getString(Category.TAG);
mCategory = TopekaDatabaseHelper.getCategoryWith(getActivity(), categoryId);
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
// Create a themed Context and custom LayoutInflater
// to get nicely themed views in this Fragment.
final Theme theme = mCategory.getTheme();
final ContextThemeWrapper context = new ContextThemeWrapper(getActivity(),
theme.getStyleId());
final LayoutInflater themedInflater = LayoutInflater.from(context);
return themedInflater.inflate(R.layout.fragment_quiz, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
mQuizView = (AdapterViewAnimator) view.findViewById(R.id.quiz_view);
decideOnViewToDisplay();
setQuizViewAnimations();
final AvatarView avatar = (AvatarView) view.findViewById(R.id.avatar);
setAvatarDrawable(avatar);
initProgressToolbar(view);
super.onViewCreated(view, savedInstanceState);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setQuizViewAnimations() {
if (ApiLevelHelper.isLowerThan(Build.VERSION_CODES.LOLLIPOP)) {
return;
}
mQuizView.setInAnimation(getActivity(), R.animator.slide_in_bottom);
mQuizView.setOutAnimation(getActivity(), R.animator.slide_out_top);
}
private void initProgressToolbar(View view) {
final int firstUnsolvedQuizPosition = mCategory.getFirstUnsolvedQuizPosition();
final List<Quiz> quizzes = mCategory.getQuizzes();
mQuizSize = quizzes.size();
mProgressText = (TextView) view.findViewById(R.id.progress_text);
mProgressBar = ((ProgressBar) view.findViewById(R.id.progress));
mProgressBar.setMax(mQuizSize);
setProgress(firstUnsolvedQuizPosition);
}
private void setProgress(int currentQuizPosition) {
if (!isAdded()) {
return;
}
mProgressText
.setText(getString(R.string.quiz_of_quizzes, currentQuizPosition, mQuizSize));
mProgressBar.setProgress(currentQuizPosition);
}
@SuppressWarnings("ConstantConditions")
private void setAvatarDrawable(AvatarView avatarView) {
Player player = PreferencesHelper.getPlayer(getActivity());
avatarView.setAvatar(player.getAvatar().getDrawableId());
ViewCompat.animate(avatarView)
.setInterpolator(new FastOutLinearInInterpolator())
.setStartDelay(500)
.scaleX(1)
.scaleY(1)
.start();
}
private void decideOnViewToDisplay() {
final boolean isSolved = mCategory.isSolved();
if (isSolved) {
showSummary();
if (null != mSolvedStateListener) {
mSolvedStateListener.onCategorySolved();
}
} else {
mQuizView.setAdapter(getQuizAdapter());
mQuizView.setSelection(mCategory.getFirstUnsolvedQuizPosition());
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
View focusedChild = mQuizView.getFocusedChild();
if (focusedChild instanceof ViewGroup) {
View currentView = ((ViewGroup) focusedChild).getChildAt(0);
if (currentView instanceof AbsQuizView) {
outState.putBundle(KEY_USER_INPUT, ((AbsQuizView) currentView).getUserInput());
}
}
super.onSaveInstanceState(outState);
}
@Override
public void onViewStateRestored(Bundle savedInstanceState) {
restoreQuizState(savedInstanceState);
super.onViewStateRestored(savedInstanceState);
}
private void restoreQuizState(final Bundle savedInstanceState) {
if (null == savedInstanceState) {
return;
}
mQuizView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft,
int oldTop, int oldRight, int oldBottom) {
mQuizView.removeOnLayoutChangeListener(this);
View currentChild = mQuizView.getChildAt(0);
if (currentChild instanceof ViewGroup) {
final View potentialQuizView = ((ViewGroup) currentChild).getChildAt(0);
if (potentialQuizView instanceof AbsQuizView) {
((AbsQuizView) potentialQuizView).setUserInput(savedInstanceState.
getBundle(KEY_USER_INPUT));
}
}
}
});
}
private QuizAdapter getQuizAdapter() {
if (null == mQuizAdapter) {
mQuizAdapter = new QuizAdapter(getActivity(), mCategory);
}
return mQuizAdapter;
}
/**
* Displays the next page.
*
* @return <code>true</code> if there's another quiz to solve, else <code>false</code>.
*/
public boolean showNextPage() {
if (null == mQuizView) {
return false;
}
int nextItem = mQuizView.getDisplayedChild() + 1;
setProgress(nextItem);
final int count = mQuizView.getAdapter().getCount();
if (nextItem < count) {
mQuizView.showNext();
TopekaDatabaseHelper.updateCategory(getActivity(), mCategory);
return true;
}
markCategorySolved();
return false;
}
private void markCategorySolved() {
mCategory.setSolved(true);
TopekaDatabaseHelper.updateCategory(getActivity(), mCategory);
}
public void showSummary() {
@SuppressWarnings("ConstantConditions")
final ListView scorecardView = (ListView) getView().findViewById(R.id.scorecard);
mScoreAdapter = getScoreAdapter();
scorecardView.setAdapter(mScoreAdapter);
scorecardView.setVisibility(View.VISIBLE);
mQuizView.setVisibility(View.GONE);
}
public boolean hasSolvedStateListener() {
return mSolvedStateListener != null;
}
public void setSolvedStateListener(SolvedStateListener solvedStateListener) {
mSolvedStateListener = solvedStateListener;
if (mCategory.isSolved() && null != mSolvedStateListener) {
mSolvedStateListener.onCategorySolved();
}
}
private ScoreAdapter getScoreAdapter() {
if (null == mScoreAdapter) {
mScoreAdapter = new ScoreAdapter(mCategory);
}
return mScoreAdapter;
}
/**
* Interface definition for a callback to be invoked when the quiz is started.
*/
public interface SolvedStateListener {
/**
* This method will be invoked when the category has been solved.
*/
void onCategorySolved();
}
}