diff --git a/app/src/main/java/com/google/samples/apps/topeka/activity/QuizActivity.java b/app/src/main/java/com/google/samples/apps/topeka/activity/QuizActivity.java
index 8026f5f2..cabd24eb 100644
--- a/app/src/main/java/com/google/samples/apps/topeka/activity/QuizActivity.java
+++ b/app/src/main/java/com/google/samples/apps/topeka/activity/QuizActivity.java
@@ -202,7 +202,7 @@ public void onAnimationEnd(Animator animation) {
}
private void showQuizFabWithDoneIcon() {
- mQuizFab.setImageResource(R.drawable.ic_done);
+ mQuizFab.setImageResource(R.drawable.ic_tick);
mQuizFab.setId(R.id.quiz_done);
mQuizFab.setVisibility(View.VISIBLE);
mQuizFab.setScaleX(0);
diff --git a/app/src/main/java/com/google/samples/apps/topeka/adapter/CategoryAdapter.java b/app/src/main/java/com/google/samples/apps/topeka/adapter/CategoryAdapter.java
index 79879c4a..bb5a4962 100644
--- a/app/src/main/java/com/google/samples/apps/topeka/adapter/CategoryAdapter.java
+++ b/app/src/main/java/com/google/samples/apps/topeka/adapter/CategoryAdapter.java
@@ -152,7 +152,7 @@ private Drawable loadTintedCategoryDrawable(Category category, int categoryImage
* @return The tinted check mark
*/
private Drawable loadTintedDoneDrawable() {
- final Drawable done = mActivity.getDrawable(R.drawable.ic_done);
+ final Drawable done = mActivity.getDrawable(R.drawable.ic_tick);
tintDrawable(done, android.R.color.white);
return done;
}
diff --git a/app/src/main/java/com/google/samples/apps/topeka/adapter/ScoreAdapter.java b/app/src/main/java/com/google/samples/apps/topeka/adapter/ScoreAdapter.java
index 56b1944f..78c97065 100644
--- a/app/src/main/java/com/google/samples/apps/topeka/adapter/ScoreAdapter.java
+++ b/app/src/main/java/com/google/samples/apps/topeka/adapter/ScoreAdapter.java
@@ -96,14 +96,14 @@ private void setSolvedStateForQuiz(ImageView solvedState, int position) {
private Drawable getSuccessIcon(Context context) {
if (null == mSuccessIcon) {
- mSuccessIcon = loadAndTint(context, R.drawable.ic_done, R.color.theme_green_primary);
+ mSuccessIcon = loadAndTint(context, R.drawable.ic_tick, R.color.theme_green_primary);
}
return mSuccessIcon;
}
private Drawable getFailedIcon(Context context) {
if (null == mFailedIcon) {
- mFailedIcon = loadAndTint(context, R.drawable.ic_fail, R.color.theme_red_primary);
+ mFailedIcon = loadAndTint(context, R.drawable.ic_cross, R.color.theme_red_primary);
}
return mFailedIcon;
}
diff --git a/app/src/main/java/com/google/samples/apps/topeka/helper/TransitionHelper.java b/app/src/main/java/com/google/samples/apps/topeka/helper/TransitionHelper.java
index 641fc437..1a998936 100644
--- a/app/src/main/java/com/google/samples/apps/topeka/helper/TransitionHelper.java
+++ b/app/src/main/java/com/google/samples/apps/topeka/helper/TransitionHelper.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2015 Google Inc. All Rights Reserved.
+ * 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
+ * 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,
diff --git a/app/src/main/java/com/google/samples/apps/topeka/widget/AvatarView.java b/app/src/main/java/com/google/samples/apps/topeka/widget/AvatarView.java
index 8720687a..fdf3d131 100644
--- a/app/src/main/java/com/google/samples/apps/topeka/widget/AvatarView.java
+++ b/app/src/main/java/com/google/samples/apps/topeka/widget/AvatarView.java
@@ -1,3 +1,18 @@
+/*
+ * 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.widget;
import com.google.samples.apps.topeka.R;
diff --git a/app/src/main/java/com/google/samples/apps/topeka/widget/fab/CheckableFab.java b/app/src/main/java/com/google/samples/apps/topeka/widget/fab/CheckableFab.java
new file mode 100644
index 00000000..41186766
--- /dev/null
+++ b/app/src/main/java/com/google/samples/apps/topeka/widget/fab/CheckableFab.java
@@ -0,0 +1,72 @@
+/*
+ * 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.widget.fab;
+
+import com.google.samples.apps.topeka.R;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.Checkable;
+
+public class CheckableFab extends FloatingActionButton implements Checkable {
+
+ private static final int[] CHECKED = {android.R.attr.state_checked};
+
+ private boolean mIsChecked = true;
+
+
+ public CheckableFab(Context context) {
+ this(context, null);
+ }
+
+ public CheckableFab(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public CheckableFab(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ setImageResource(R.drawable.answer_quiz_fab);
+ }
+
+ @Override
+ public int[] onCreateDrawableState(int extraSpace) {
+ final int[] drawableState = super.onCreateDrawableState(++extraSpace);
+ if (mIsChecked) {
+ mergeDrawableStates(drawableState, CHECKED);
+ }
+ return drawableState;
+ }
+
+ @Override
+ public void setChecked(boolean checked) {
+ if (mIsChecked == checked) {
+ return;
+ }
+ mIsChecked = checked;
+ refreshDrawableState();
+ }
+
+ @Override
+ public boolean isChecked() {
+ return mIsChecked;
+ }
+
+ @Override
+ public void toggle() {
+ setChecked(!mIsChecked);
+ }
+}
diff --git a/app/src/main/java/com/google/samples/apps/topeka/widget/fab/DoneFab.java b/app/src/main/java/com/google/samples/apps/topeka/widget/fab/DoneFab.java
index 55b59b3d..23bc619e 100644
--- a/app/src/main/java/com/google/samples/apps/topeka/widget/fab/DoneFab.java
+++ b/app/src/main/java/com/google/samples/apps/topeka/widget/fab/DoneFab.java
@@ -32,6 +32,6 @@ public DoneFab(Context context, AttributeSet attrs) {
public DoneFab(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- setImageResource(R.drawable.ic_done);
+ setImageResource(R.drawable.ic_tick);
}
}
diff --git a/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/AbsQuizView.java b/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/AbsQuizView.java
index 216c72c8..67883e11 100644
--- a/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/AbsQuizView.java
+++ b/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/AbsQuizView.java
@@ -37,8 +37,7 @@
import com.google.samples.apps.topeka.activity.QuizActivity;
import com.google.samples.apps.topeka.model.Category;
import com.google.samples.apps.topeka.model.quiz.Quiz;
-import com.google.samples.apps.topeka.widget.fab.DoneFab;
-import com.google.samples.apps.topeka.widget.fab.FloatingActionButton;
+import com.google.samples.apps.topeka.widget.fab.CheckableFab;
/**
* This is the base class for displaying a {@link com.google.samples.apps.topeka.model.quiz.Quiz}.
@@ -87,7 +86,7 @@ public Integer get(FrameLayout object) {
private final int mScaleAnimationDuration;
private boolean mAnswered;
private TextView mQuestionView;
- private FloatingActionButton mSubmitAnswer;
+ private CheckableFab mSubmitAnswer;
/**
* Enables creation of views for quizzes.
@@ -178,9 +177,9 @@ private void addFloatingActionButton() {
addView(mSubmitAnswer, fabLayoutParams);
}
- private FloatingActionButton getSubmitButton(Context context) {
+ private CheckableFab getSubmitButton(Context context) {
if (null == mSubmitAnswer) {
- mSubmitAnswer = new DoneFab(context);
+ mSubmitAnswer = new CheckableFab(context);
mSubmitAnswer.setId(R.id.submitAnswer);
mSubmitAnswer.setVisibility(GONE);
mSubmitAnswer.setScaleY(0);
@@ -290,43 +289,70 @@ private void submitAnswer(final View v) {
*/
private void performScoreAnimation(final boolean answerCorrect) {
- // Decide on the color and icon to use.
- final int backgroundColor = getResources().getColor(answerCorrect ?
- R.color.green : R.color.red);
- final int imageResId = answerCorrect ? R.drawable.ic_done : R.drawable.ic_fail;
+ mSubmitAnswer.setChecked(answerCorrect);
- // Set color, duration and interpolator for the color change. Then start the animation.
- final ObjectAnimator fabColorAnimator = ObjectAnimator
- .ofArgb(mSubmitAnswer, "backgroundColor", Color.WHITE, backgroundColor);
- fabColorAnimator.setDuration(mColorAnimationDuration)
- .setInterpolator(mFastOutSlowInInterpolator);
- fabColorAnimator.start();
-
- // Set duration and interpolator for the icon change. Then start the animation.
- final ObjectAnimator iconAnimator = ObjectAnimator
- .ofArgb(mSubmitAnswer, "imageResource", R.drawable.ic_done, imageResId);
- iconAnimator.setDuration(mIconAnimationDuration)
- .setInterpolator(mFastOutSlowInInterpolator);
- iconAnimator.start();
+ // Decide which background color to use.
+ final int backgroundColor = getResources()
+ .getColor(answerCorrect ? R.color.green : R.color.red);
+ animateFabBackgroundColor(backgroundColor);
+ hideFab();
+ resizeView();
+ moveViewOffScreen(answerCorrect);
+ // Animate the foreground color to match the background color.
+ // This overlays all content within the current view.
+ animateForegroundColor(backgroundColor);
+ }
- // Hide the FAB.
+ private void hideFab() {
mSubmitAnswer.animate()
.setDuration(mScaleAnimationDuration)
.setStartDelay(mIconAnimationDuration * 2)
.scaleX(0f)
.scaleY(0f)
- .setInterpolator(mLinearOutSlowInInterpolator);
+ .setInterpolator(mLinearOutSlowInInterpolator)
+ .start();
+ }
- // Prepare for take off.
+ private void resizeView() {
final float widthHeightRatio = (float) getHeight() / (float) getWidth();
- setElevation(getResources().getDimension(R.dimen.elevation_header));
- // Animate the current view off the screen.
- animate().
- setDuration(500)
+ // Animate X and Y scaling separately to allow different start delays.
+ animate()
+ .scaleY(.5f / widthHeightRatio)
+ .setDuration(300)
.setStartDelay(750)
+ .start();
+ animate()
.scaleX(.5f)
- .scaleY(.5f / widthHeightRatio)
+ .setDuration(300)
+ .setStartDelay(800)
+ .start();
+ }
+
+ private void animateFabBackgroundColor(int backgroundColor) {
+ // Set color, duration and interpolator for the color change. Then start the animation.
+ final ObjectAnimator fabColorAnimator = ObjectAnimator
+ .ofArgb(mSubmitAnswer, "backgroundColor", Color.WHITE, backgroundColor);
+ fabColorAnimator.setDuration(mColorAnimationDuration)
+ .setInterpolator(mFastOutSlowInInterpolator);
+ fabColorAnimator.start();
+ }
+
+ private void animateForegroundColor(int targetColor) {
+ final ObjectAnimator foregroundAnimator = ObjectAnimator
+ .ofArgb(this, FOREGROUND_COLOR, Color.WHITE, targetColor);
+ foregroundAnimator
+ .setDuration(200)
+ .setInterpolator(mLinearOutSlowInInterpolator);
+ foregroundAnimator.setStartDelay(750);
+ foregroundAnimator.start();
+ }
+
+ private void moveViewOffScreen(final boolean answerCorrect) {
+ // Animate the current view off the screen.
+ animate()
+ .setDuration(200)
+ .setStartDelay(1200)
.setInterpolator(mLinearOutSlowInInterpolator)
.withEndAction(new Runnable() {
@Override
@@ -336,17 +362,8 @@ public void run() {
((QuizActivity) getContext()).proceed();
}
}
- });
-
- // Animate the foreground color to match the background color.
- // This overlays all content within the current view.
- final ObjectAnimator foregroundAnimator = ObjectAnimator
- .ofArgb(this, FOREGROUND_COLOR, Color.WHITE, backgroundColor);
- foregroundAnimator.setDuration(200)
- .setInterpolator(mLinearOutSlowInInterpolator);
- foregroundAnimator.setStartDelay(750);
- foregroundAnimator.start();
-
+ })
+ .start();
}
private void setMinHeightInternal(View view, @DimenRes int resId) {
diff --git a/app/src/main/res/drawable/ic_fail.xml b/app/src/main/res/animator-v21/cross_to_tick_line_1.xml
similarity index 60%
rename from app/src/main/res/drawable/ic_fail.xml
rename to app/src/main/res/animator-v21/cross_to_tick_line_1.xml
index 8e49d5e8..34877d85 100644
--- a/app/src/main/res/drawable/ic_fail.xml
+++ b/app/src/main/res/animator-v21/cross_to_tick_line_1.xml
@@ -14,12 +14,11 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-
-
+
diff --git a/app/src/main/res/animator-v21/cross_to_tick_line_2.xml b/app/src/main/res/animator-v21/cross_to_tick_line_2.xml
new file mode 100644
index 00000000..f69b1654
--- /dev/null
+++ b/app/src/main/res/animator-v21/cross_to_tick_line_2.xml
@@ -0,0 +1,24 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_done.xml b/app/src/main/res/animator-v21/rotate_cross_to_tick.xml
similarity index 65%
rename from app/src/main/res/drawable/ic_done.xml
rename to app/src/main/res/animator-v21/rotate_cross_to_tick.xml
index e9fff018..77d2b040 100644
--- a/app/src/main/res/drawable/ic_done.xml
+++ b/app/src/main/res/animator-v21/rotate_cross_to_tick.xml
@@ -14,12 +14,10 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-
-
\ No newline at end of file
+
diff --git a/app/src/main/res/animator-v21/rotate_tick_to_cross.xml b/app/src/main/res/animator-v21/rotate_tick_to_cross.xml
new file mode 100644
index 00000000..9d9e98b8
--- /dev/null
+++ b/app/src/main/res/animator-v21/rotate_tick_to_cross.xml
@@ -0,0 +1,23 @@
+
+
+
diff --git a/app/src/main/res/animator-v21/tick_to_cross_line_1.xml b/app/src/main/res/animator-v21/tick_to_cross_line_1.xml
new file mode 100644
index 00000000..a798e7cd
--- /dev/null
+++ b/app/src/main/res/animator-v21/tick_to_cross_line_1.xml
@@ -0,0 +1,24 @@
+
+
+
diff --git a/app/src/main/res/animator-v21/tick_to_cross_line_2.xml b/app/src/main/res/animator-v21/tick_to_cross_line_2.xml
new file mode 100644
index 00000000..e38e7aa0
--- /dev/null
+++ b/app/src/main/res/animator-v21/tick_to_cross_line_2.xml
@@ -0,0 +1,24 @@
+
+
+
diff --git a/app/src/main/res/drawable-v21/answer_quiz_fab.xml b/app/src/main/res/drawable-v21/answer_quiz_fab.xml
new file mode 100644
index 00000000..6c436332
--- /dev/null
+++ b/app/src/main/res/drawable-v21/answer_quiz_fab.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable-v21/avd_cross_to_tick.xml b/app/src/main/res/drawable-v21/avd_cross_to_tick.xml
new file mode 100644
index 00000000..7375e2a1
--- /dev/null
+++ b/app/src/main/res/drawable-v21/avd_cross_to_tick.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable-v21/avd_tick_to_cross.xml b/app/src/main/res/drawable-v21/avd_tick_to_cross.xml
new file mode 100644
index 00000000..71b9280c
--- /dev/null
+++ b/app/src/main/res/drawable-v21/avd_tick_to_cross.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/answer_quiz_fab.xml b/app/src/main/res/drawable/answer_quiz_fab.xml
new file mode 100644
index 00000000..d20f76f0
--- /dev/null
+++ b/app/src/main/res/drawable/answer_quiz_fab.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_cross.xml b/app/src/main/res/drawable/ic_cross.xml
new file mode 100644
index 00000000..a5f0b16c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_cross.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_tick.xml b/app/src/main/res/drawable/ic_tick.xml
new file mode 100644
index 00000000..30d2ef97
--- /dev/null
+++ b/app/src/main/res/drawable/ic_tick.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_scorecard.xml b/app/src/main/res/layout/item_scorecard.xml
index 6aa837fd..79ba8a0b 100644
--- a/app/src/main/res/layout/item_scorecard.xml
+++ b/app/src/main/res/layout/item_scorecard.xml
@@ -33,7 +33,7 @@
android:layout_marginEnd="@dimen/spacing_double"
android:layout_marginStart="@dimen/spacing_double"
android:contentDescription="@null"
- android:src="@drawable/ic_done" />
+ android:src="@drawable/ic_tick" />
+
+
+
+
+ 24
+ 24
+ 12
+ 12
+ 2
+ M19.6,7 L10.4,16.2
+ M4.8,13.4 L9,17.6
+ M17.6,6.4 L6.4,17.6
+ M6.4,6.4 L17.6,17.6
+
+
+ groupTickCross
+ line_1
+ line_2
+
+
+ @android:color/black
+
+
+ 450
+
+