diff --git a/.google/packaging.yaml b/.google/packaging.yaml
index 8cf1302c..baace339 100644
--- a/.google/packaging.yaml
+++ b/.google/packaging.yaml
@@ -26,5 +26,4 @@ apiRefs:
- android:android.view.ViewOutlineProvider
- android:android.view.ContextThemeWrapper
-
license: apache2-google
diff --git a/README.markdown b/README.markdown
index f875bbc6..1e92cd72 100644
--- a/README.markdown
+++ b/README.markdown
@@ -4,14 +4,29 @@ A fun to play quiz that showcases material design on Android
### Introduction
-Material design is a new system for visual, interaction and motion design. We
-originally launched the [Topeka web app](https://github.com/Polymer/topeka)
-as an Open Source example of material design on the web.
-
+Material design is a new system for visual, interaction and motion design.
The Android version of Topeka demonstrates that the same branding and material
design principles can be used to create a consistent experience across
-platforms. You can read more about it on the
-[Android Developers
+platforms.
+
+We originally launched the [Topeka web app](https://github.com/Polymer/topeka)
+as an Open Source example of material design on the web.
+
+The current release of Topeka is available to users down to API level 16 aka [Jelly
+Bean](http://developer.android.com/about/versions/android-4.1.html).
+This is being accomplished by utilizing several [support
+libraries](https://developer.android.com/tools/support-library/index.html).
+Especially
+[AppCompat](https://developer.android.com/tools/support-library/features.html#v7-appcompat)
+and the [design support
+library](https://developer.android.com/tools/support-library/features.html#design)
+play important roles.
+
+Topeka also features a set of [Espresso
+tests](http://google.github.io/android-testing-support-library) which can be
+executed with the `connectedAndroidTest` gradle task.
+
+You can read more about the project on the [Android Developers
blog](http://android-developers.blogspot.co.uk/2015/06/more-material-design-with-topeka-for_16.html).
### Screenshots
@@ -22,7 +37,8 @@ blog](http://android-developers.blogspot.co.uk/2015/06/more-material-design-with
### Getting Started
-Clone this repository, enter the top level directory and run
+ * The counter may be incremented or decremented from any thread. If it reaches an illogical state
+ * (like counter less than zero) it will throw an IllegalStateException.
+ *
+ * This class can then be used to wrap up operations that while in progress should block tests from
+ * accessing the UI.
+ * ./gradlew tasks
to get an overview of all the tasks available for this project.
+Clone this repository, enter the top level directory and run ./gradlew tasks
+to get an overview of all the tasks available for this project.
Some important tasks are:
diff --git a/app/build.gradle b/app/build.gradle
index 294a3316..b89b44ce 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -22,7 +22,7 @@ android {
defaultConfig {
applicationId "com.google.samples.apps.topeka"
- minSdkVersion 21
+ minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
@@ -31,7 +31,7 @@ android {
buildTypes {
release {
- minifyEnabled false
+ minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
@@ -46,7 +46,13 @@ dependencies {
compile 'com.android.support:cardview-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
compile 'com.android.support:recyclerview-v7:23.0.1'
+ compile 'com.android.support.test.espresso:espresso-idling-resource:2.2.1'
testCompile 'junit:junit:4.12'
- androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
+
+ androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.1') {
+ exclude module: 'espresso-idling-resource'
+ }
+ androidTestCompile 'com.android.support.test:rules:0.4'
+ androidTestCompile 'com.android.support.test:runner:0.4'
androidTestCompile 'org.hamcrest:hamcrest-core:1.3'
}
diff --git a/app/src/androidTest/java/com/google/samples/apps/topeka/activity/CategorySelectionActivityTest.java b/app/src/androidTest/java/com/google/samples/apps/topeka/activity/CategorySelectionActivityTest.java
new file mode 100644
index 00000000..e7395f04
--- /dev/null
+++ b/app/src/androidTest/java/com/google/samples/apps/topeka/activity/CategorySelectionActivityTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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.activity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.google.samples.apps.topeka.R;
+import com.google.samples.apps.topeka.helper.PreferencesHelper;
+import com.google.samples.apps.topeka.model.Avatar;
+import com.google.samples.apps.topeka.model.Category;
+import com.google.samples.apps.topeka.model.Player;
+import com.google.samples.apps.topeka.persistence.TopekaDatabaseHelper;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+import static android.support.test.espresso.Espresso.onData;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static junit.framework.Assert.assertFalse;
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class CategorySelectionActivityTest {
+
+ private Context mTargetContext;
+ private List
+ * {@code
+ * public interface FooServer {
+ * public Foo newFoo();
+ * public void updateFoo(Foo foo);
+ * }
+ *
+ * public DecoratedFooServer implements FooServer {
+ * private final FooServer realFooServer;
+ * private final CountingIdlingResource fooServerIdlingResource;
+ *
+ * public DecoratedFooServer(FooServer realFooServer,
+ * CountingIdlingResource fooServerIdlingResource) {
+ * this.realFooServer = checkNotNull(realFooServer);
+ * this.fooServerIdlingResource = checkNotNull(fooServerIdlingResource);
+ * }
+ *
+ * public Foo newFoo() {
+ * fooServerIdlingResource.increment();
+ * try {
+ * return realFooServer.newFoo();
+ * } finally {
+ * fooServerIdlingResource.decrement();
+ * }
+ * }
+ *
+ * public void updateFoo(Foo foo) {
+ * fooServerIdlingResource.increment();
+ * try {
+ * realFooServer.updateFoo(foo);
+ * } finally {
+ * fooServerIdlingResource.decrement();
+ * }
+ * }
+ * }
+ * }
+ *
+ *
+ * Then in your test setup:
+ *
+ * {@code
+ * public void setUp() throws Exception {
+ * super.setUp();
+ * FooServer realServer = FooApplication.getFooServer();
+ * CountingIdlingResource countingResource = new CountingIdlingResource("FooServerCalls");
+ * FooApplication.setFooServer(new DecoratedFooServer(realServer, countingResource));
+ * Espresso.registerIdlingResource(countingResource);
+ * }
+ * }
+ *
+ */
+@SuppressWarnings("javadoc")
+public final class CountingIdlingResource implements IdlingResource {
+ private static final String TAG = "CountingIdlingResource";
+ private final String resourceName;
+ private final AtomicInteger counter = new AtomicInteger(0);
+ private final boolean debugCounting;
+ // written from main thread, read from any thread.
+ private volatile ResourceCallback resourceCallback;
+ // read/written from any thread - used for debugging messages.
+ private volatile long becameBusyAt = 0;
+ private volatile long becameIdleAt = 0;
+
+ /**
+ * Creates a CountingIdlingResource without debug tracing.
+ *
+ * @param resourceName the resource name this resource should report to Espresso.
+ */
+ public CountingIdlingResource(String resourceName) {
+ this(resourceName, false);
+ }
+
+ /**
+ * Creates a CountingIdlingResource.
+ *
+ * @param resourceName the resource name this resource should report to Espresso.
+ * @param debugCounting if true increment & decrement calls will print trace information to
+ * logs.
+ */
+ public CountingIdlingResource(String resourceName, boolean debugCounting) {
+ if (TextUtils.isEmpty(resourceName)) {
+ throw new IllegalArgumentException("Resource name must not be empty or null");
+ }
+ this.resourceName = resourceName;
+ this.debugCounting = debugCounting;
+ }
+
+ @Override
+ public String getName() {
+ return resourceName;
+ }
+
+ @Override
+ public boolean isIdleNow() {
+ return counter.get() == 0;
+ }
+
+ @Override
+ public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
+ this.resourceCallback = resourceCallback;
+ }
+
+ /**
+ * Increments the count of in-flight transactions to the resource being monitored.
+ *
+ * This method can be called from any thread.
+ */
+ public void increment() {
+ int counterVal = counter.getAndIncrement();
+ if (0 == counterVal) {
+ becameBusyAt = SystemClock.uptimeMillis();
+ }
+ if (debugCounting) {
+ Log.i(TAG, "Resource: " + resourceName + " in-use-count incremented to: "
+ + (counterVal + 1));
+ }
+ }
+
+ /**
+ * Decrements the count of in-flight transactions to the resource being monitored.
+ *
+ * If this operation results in the counter falling below 0 - an exception is raised.
+ *
+ * @throws IllegalStateException if the counter is below 0.
+ */
+ public void decrement() {
+ int counterVal = counter.decrementAndGet();
+ if (counterVal == 0) {
+ // we've gone from non-zero to zero. That means we're idle now! Tell espresso.
+ if (null != resourceCallback) {
+ resourceCallback.onTransitionToIdle();
+ }
+ becameIdleAt = SystemClock.uptimeMillis();
+ }
+ if (debugCounting) {
+ if (counterVal == 0) {
+ Log.i(TAG, "Resource: " + resourceName + " went idle! (Time spent not idle: "
+ + (becameIdleAt - becameBusyAt) + ")");
+ } else {
+ Log.i(TAG, "Resource: " + resourceName + " in-use-count decremented to: "
+ + counterVal);
+ }
+ }
+ if (counterVal < 0) {
+ throw new IllegalArgumentException("Counter has been corrupted!");
+ }
+ }
+
+ /**
+ * Prints the current state of this resource to the logcat at info level.
+ */
+ public void dumpStateToLogs() {
+ StringBuilder message = new StringBuilder("Resource: ")
+ .append(resourceName)
+ .append(" inflight transaction count: ")
+ .append(counter.get());
+ if (0 == becameBusyAt) {
+ Log.i(TAG, message.append(" and has never been busy!").toString());
+ } else {
+ message.append(" and was last busy at: ")
+ .append(becameBusyAt);
+ if (0 == becameIdleAt) {
+ Log.w(TAG, message.append(" AND NEVER WENT IDLE!").toString());
+ } else {
+ message.append(" and last went idle at: ")
+ .append(becameIdleAt);
+ Log.i(TAG, message.toString());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/google/samples/apps/topeka/activity/CategorySelectionActivity.java b/app/src/main/java/com/google/samples/apps/topeka/activity/CategorySelectionActivity.java
index b3b40aa9..e8c83aa6 100644
--- a/app/src/main/java/com/google/samples/apps/topeka/activity/CategorySelectionActivity.java
+++ b/app/src/main/java/com/google/samples/apps/topeka/activity/CategorySelectionActivity.java
@@ -19,6 +19,8 @@
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
@@ -39,15 +41,20 @@ public class CategorySelectionActivity extends AppCompatActivity {
private static final String EXTRA_PLAYER = "player";
public static void start(Context context, Player player, ActivityOptionsCompat options) {
- Intent starter = new Intent(context, CategorySelectionActivity.class);
- starter.putExtra(EXTRA_PLAYER, player);
+ Intent starter = getStartIntent(context, player);
context.startActivity(starter, options.toBundle());
}
public static void start(Context context, Player player) {
+ Intent starter = getStartIntent(context, player);
+ context.startActivity(starter);
+ }
+
+ @NonNull
+ static Intent getStartIntent(Context context, Player player) {
Intent starter = new Intent(context, CategorySelectionActivity.class);
starter.putExtra(EXTRA_PLAYER, player);
- context.startActivity(starter);
+ return starter;
}
@Override
@@ -56,6 +63,9 @@ protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_category_selection);
Player player = getIntent().getParcelableExtra(EXTRA_PLAYER);
+ if (!PreferencesHelper.isSignedIn(this) && player != null) {
+ PreferencesHelper.writeToPreferences(this, player);
+ }
setUpToolbar(player);
if (savedInstanceState == null) {
attachCategoryGridFragment();
@@ -78,7 +88,7 @@ private void setUpToolbar(Player player) {
//noinspection ConstantConditions
getSupportActionBar().setDisplayShowTitleEnabled(false);
final AvatarView avatarView = (AvatarView) toolbar.findViewById(R.id.avatar);
- avatarView.setImageResource(player.getAvatar().getDrawableId());
+ avatarView.setAvatar(player.getAvatar().getDrawableId());
//noinspection PrivateResource
((TextView) toolbar.findViewById(R.id.title)).setText(getDisplayName(player));
}
@@ -104,7 +114,7 @@ private void signOut() {
PreferencesHelper.signOut(this);
TopekaDatabaseHelper.reset(this);
SignInActivity.start(this, false, null);
- finishAfterTransition();
+ ActivityCompat.finishAfterTransition(this);
}
private String getDisplayName(Player player) {
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 db1fbc5e..f1f09310 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
@@ -18,30 +18,33 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
+import android.support.annotation.VisibleForTesting;
import android.support.design.widget.FloatingActionButton;
+import android.support.test.espresso.contrib.CountingIdlingResource;
+import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
+import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
-import android.transition.Transition;
-import android.transition.TransitionInflater;
import android.util.Log;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.Window;
-import android.view.WindowManager;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.ImageView;
import com.google.samples.apps.topeka.R;
import com.google.samples.apps.topeka.fragment.QuizFragment;
+import com.google.samples.apps.topeka.helper.ApiLevelHelper;
import com.google.samples.apps.topeka.model.Category;
import com.google.samples.apps.topeka.persistence.TopekaDatabaseHelper;
@@ -54,6 +57,7 @@ public class QuizActivity extends AppCompatActivity {
private static final String STATE_IS_PLAYING = "isPlaying";
private static final int UNDEFINED = -1;
private static final String FRAGMENT_TAG = "Quiz";
+
private Interpolator mInterpolator;
private String mCategoryId;
private QuizFragment mQuizFragment;
@@ -62,6 +66,7 @@ public class QuizActivity extends AppCompatActivity {
private boolean mSavedStateIsPlaying;
private ImageView mIcon;
private Animator mCircularReveal;
+ private CountingIdlingResource mCountingIdlingResource;
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
@@ -74,12 +79,12 @@ public void onClick(final View v) {
submitAnswer();
break;
case R.id.quiz_done:
- finishAfterTransition();
+ ActivityCompat.finishAfterTransition(QuizActivity.this);
break;
case UNDEFINED:
final CharSequence contentDescription = v.getContentDescription();
- if (contentDescription != null && contentDescription.equals(
- getString(R.string.up))) {
+ if (contentDescription != null && contentDescription
+ .equals(getString(R.string.up))) {
onBackPressed();
break;
}
@@ -99,15 +104,9 @@ public static Intent getStartIntent(Context context, Category category) {
@Override
protected void onCreate(Bundle savedInstanceState) {
- // Inflate and set the enter transition for this activity.
- final Transition sharedElementEnterTransition = TransitionInflater.from(this)
- .inflateTransition(R.transition.quiz_enter);
- getWindow().setSharedElementEnterTransition(sharedElementEnterTransition);
-
+ mCountingIdlingResource = new CountingIdlingResource("Quiz");
mCategoryId = getIntent().getStringExtra(Category.TAG);
- //noinspection ResourceType
- mInterpolator = AnimationUtils.loadInterpolator(this,
- android.R.interpolator.fast_out_slow_in);
+ mInterpolator = new FastOutSlowInInterpolator();
if (null != savedInstanceState) {
mSavedStateIsPlaying = savedInstanceState.getBoolean(STATE_IS_PLAYING);
}
@@ -153,9 +152,12 @@ public void onBackPressed() {
.setInterpolator(mInterpolator)
.setStartDelay(100)
.setListener(new ViewPropertyAnimatorListenerAdapter() {
+ @SuppressLint("NewApi")
@Override
public void onAnimationEnd(View view) {
- if (isFinishing() || isDestroyed()) {
+ if (isFinishing() ||
+ (ApiLevelHelper.isAtLeast(Build.VERSION_CODES.JELLY_BEAN_MR1)
+ && isDestroyed())) {
return;
}
QuizActivity.super.onBackPressed();
@@ -169,7 +171,24 @@ private void startQuizFromClickOn(final View clickedView) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.quiz_fragment_container, mQuizFragment, FRAGMENT_TAG).commit();
final View fragmentContainer = findViewById(R.id.quiz_fragment_container);
+ revealFragmentContainer(clickedView, fragmentContainer);
+ // the toolbar should not have more elevation than the content while playing
+ setToolbarElevation(false);
+ }
+
+ private void revealFragmentContainer(final View clickedView, final View fragmentContainer) {
+ if (ApiLevelHelper.isAtLeast(Build.VERSION_CODES.LOLLIPOP)) {
+ revealFragmentContainerLollipop(clickedView, fragmentContainer);
+ } else {
+ fragmentContainer.setVisibility(View.VISIBLE);
+ clickedView.setVisibility(View.GONE);
+ mIcon.setVisibility(View.GONE);
+ }
+ }
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private void revealFragmentContainerLollipop(final View clickedView,
+ final View fragmentContainer) {
prepareCircularReveal(clickedView, fragmentContainer);
ViewCompat.animate(clickedView)
.scaleX(0)
@@ -184,15 +203,13 @@ public void onAnimationEnd(View view) {
}
})
.start();
-
- // the toolbar should not have more elevation than the content while playing
- mToolbar.setElevation(0);
}
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void prepareCircularReveal(View startView, View targetView) {
int centerX = (startView.getLeft() + startView.getRight()) / 2;
int centerY = (startView.getTop() + startView.getBottom()) / 2;
- int finalRadius = Math.max(targetView.getWidth(), targetView.getHeight());
+ float finalRadius = (float) Math.hypot((double) centerX, (double) centerY);
mCircularReveal = ViewAnimationUtils.createCircularReveal(
targetView, centerX, centerY, 0, finalRadius);
@@ -205,8 +222,11 @@ public void onAnimationEnd(Animator animation) {
});
}
- public void elevateToolbar() {
- mToolbar.setElevation(getResources().getDimension(R.dimen.elevation_header));
+ public void setToolbarElevation(boolean shouldElevate) {
+ if (ApiLevelHelper.isAtLeast(Build.VERSION_CODES.LOLLIPOP)) {
+ mToolbar.setElevation(shouldElevate ?
+ getResources().getDimension(R.dimen.elevation_header) : 0);
+ }
}
private void initQuizFragment() {
@@ -214,7 +234,7 @@ private void initQuizFragment() {
new QuizFragment.SolvedStateListener() {
@Override
public void onCategorySolved() {
- elevateToolbar();
+ setToolbarElevation(true);
displayDoneFab();
}
@@ -250,8 +270,10 @@ private void showQuizFabWithDoneIcon() {
.start();
}
});
- // the toolbar should not have more elevation than the content while playing
- mToolbar.setElevation(0);
+ if (ApiLevelHelper.isAtLeast(Build.VERSION_CODES.LOLLIPOP)) {
+ // the toolbar should not have more elevation than the content while playing
+ setToolbarElevation(false);
+ }
}
/**
@@ -261,13 +283,20 @@ public void proceed() {
submitAnswer();
}
+ /**
+ * Solely exists for testing purposes and making sure Espresso does not get confused.
+ */
+ public void lockIdlingResource() {
+ mCountingIdlingResource.increment();
+ }
+
private void submitAnswer() {
- elevateToolbar();
+ mCountingIdlingResource.decrement();
if (!mQuizFragment.showNextPage()) {
mQuizFragment.showSummary();
return;
}
- mToolbar.setElevation(0);
+ setToolbarElevation(false);
}
private void populate(String categoryId) {
@@ -277,13 +306,11 @@ private void populate(String categoryId) {
}
Category category = TopekaDatabaseHelper.getCategoryWith(this, categoryId);
setTheme(category.getTheme().getStyleId());
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ if (ApiLevelHelper.isAtLeast(Build.VERSION_CODES.LOLLIPOP)) {
Window window = getWindow();
- window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(ContextCompat.getColor(this,
category.getTheme().getPrimaryDarkColor()));
}
-
initLayout(category.getId());
initToolbar(category);
}
@@ -305,14 +332,12 @@ private void initLayout(String categoryId) {
.start();
mQuizFab = (FloatingActionButton) findViewById(R.id.fab_quiz);
mQuizFab.setImageResource(R.drawable.ic_play);
- mQuizFab.setVisibility(mSavedStateIsPlaying ? View.GONE : View.VISIBLE);
+ if (mSavedStateIsPlaying) {
+ mQuizFab.hide();
+ } else {
+ mQuizFab.show();
+ }
mQuizFab.setOnClickListener(mOnClickListener);
- ViewCompat.animate(mQuizFab)
- .scaleX(1)
- .scaleY(1)
- .setInterpolator(mInterpolator)
- .setStartDelay(400)
- .start();
}
private void initToolbar(Category category) {
@@ -323,7 +348,12 @@ private void initToolbar(Category category) {
mToolbar.setNavigationOnClickListener(mOnClickListener);
if (mSavedStateIsPlaying) {
// the toolbar should not have more elevation than the content while playing
- mToolbar.setElevation(0);
+ setToolbarElevation(false);
}
}
+
+ @VisibleForTesting
+ public CountingIdlingResource getCountingIdlingResource() {
+ return mCountingIdlingResource;
+ }
}
diff --git a/app/src/main/java/com/google/samples/apps/topeka/adapter/AvatarAdapter.java b/app/src/main/java/com/google/samples/apps/topeka/adapter/AvatarAdapter.java
index 2d3e2696..1024fe8a 100644
--- a/app/src/main/java/com/google/samples/apps/topeka/adapter/AvatarAdapter.java
+++ b/app/src/main/java/com/google/samples/apps/topeka/adapter/AvatarAdapter.java
@@ -49,7 +49,7 @@ public View getView(int position, View convertView, ViewGroup parent) {
}
private void setAvatar(AvatarView mIcon, Avatar avatar) {
- mIcon.setImageResource(avatar.getDrawableId());
+ mIcon.setAvatar(avatar.getDrawableId());
mIcon.setContentDescription(avatar.getNameForAccessibility());
}
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 c74b3309..68c56af1 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
@@ -145,8 +145,7 @@ private LayerDrawable loadSolvedIcon(Category category, int categoryImageResourc
*/
private Drawable loadTintedCategoryDrawable(Category category, int categoryImageResource) {
final Drawable categoryIcon = ContextCompat.getDrawable(mActivity, categoryImageResource);
-
- DrawableCompat.setTint(categoryIcon, category.getTheme().getPrimaryColor());
+ DrawableCompat.setTint(categoryIcon, getColor(category.getTheme().getPrimaryColor()));
return categoryIcon;
}
@@ -157,7 +156,7 @@ private Drawable loadTintedCategoryDrawable(Category category, int categoryImage
*/
private Drawable loadTintedDoneDrawable() {
final Drawable done = ContextCompat.getDrawable(mActivity, R.drawable.ic_tick);
- DrawableCompat.setTint(done, android.R.color.white);
+ DrawableCompat.setTint(done, getColor(android.R.color.white));
return done;
}
diff --git a/app/src/main/java/com/google/samples/apps/topeka/fragment/CategorySelectionFragment.java b/app/src/main/java/com/google/samples/apps/topeka/fragment/CategorySelectionFragment.java
index b0e2694b..61d0058c 100644
--- a/app/src/main/java/com/google/samples/apps/topeka/fragment/CategorySelectionFragment.java
+++ b/app/src/main/java/com/google/samples/apps/topeka/fragment/CategorySelectionFragment.java
@@ -18,6 +18,7 @@
import android.app.Activity;
import android.os.Bundle;
+import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v4.app.Fragment;
import android.support.v4.util.Pair;
@@ -82,7 +83,8 @@ private void startQuizActivityWithTransition(Activity activity, View toolbar,
// Start the activity with the participants, animating from one to the other.
final Bundle transitionBundle = sceneTransitionAnimation.toBundle();
- activity.startActivity(QuizActivity.getStartIntent(activity, category), transitionBundle);
+ ActivityCompat.startActivity(getActivity(),
+ QuizActivity.getStartIntent(activity, category), transitionBundle);
}
}
diff --git a/app/src/main/java/com/google/samples/apps/topeka/fragment/QuizFragment.java b/app/src/main/java/com/google/samples/apps/topeka/fragment/QuizFragment.java
index c53f4da4..e29ebc8d 100644
--- a/app/src/main/java/com/google/samples/apps/topeka/fragment/QuizFragment.java
+++ b/app/src/main/java/com/google/samples/apps/topeka/fragment/QuizFragment.java
@@ -16,8 +16,12 @@
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;
@@ -30,6 +34,7 @@
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;
@@ -94,14 +99,22 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
mQuizView = (AdapterViewAnimator) view.findViewById(R.id.quiz_view);
decideOnViewToDisplay();
- mQuizView.setInAnimation(getActivity(), R.animator.slide_in_bottom);
- mQuizView.setOutAnimation(getActivity(), R.animator.slide_out_top);
+ 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 Listtrue
if the calling version is at least apiLevel
.
+ * Else false
is returned.
+ */
+ public static boolean isAtLeast(int apiLevel) {
+ return Build.VERSION.SDK_INT >= apiLevel;
+ }
+
+ /**
+ * Checks if the current api level is at lower than the provided value.
+ *
+ * @param apiLevel One of the values within {@link Build.VERSION_CODES}.
+ * @return true
if the calling version is lower than apiLevel
.
+ * Else false
is returned.
+ */
+ public static boolean isLowerThan(int apiLevel) {
+ return Build.VERSION.SDK_INT < apiLevel;
+ }
+}
diff --git a/app/src/main/java/com/google/samples/apps/topeka/model/Theme.java b/app/src/main/java/com/google/samples/apps/topeka/model/Theme.java
index 12112bf7..fd1b8805 100644
--- a/app/src/main/java/com/google/samples/apps/topeka/model/Theme.java
+++ b/app/src/main/java/com/google/samples/apps/topeka/model/Theme.java
@@ -33,36 +33,38 @@
public enum Theme {
topeka(R.color.topeka_primary, R.color.topeka_primary_dark,
R.color.theme_blue_background, R.color.theme_blue_text,
- R.style.Topeka),
+ R.color.topeka_accent, R.style.Topeka),
blue(R.color.theme_blue_primary, R.color.theme_blue_primary_dark,
R.color.theme_blue_background, R.color.theme_blue_text,
- R.style.Topeka_Blue),
+ R.color.theme_blue_accent, R.style.Topeka_Blue),
green(R.color.theme_green_primary, R.color.theme_green_primary_dark,
R.color.theme_green_background, R.color.theme_green_text,
- R.style.Topeka_Green),
+ R.color.theme_green_accent, R.style.Topeka_Green),
purple(R.color.theme_purple_primary, R.color.theme_purple_primary_dark,
R.color.theme_purple_background, R.color.theme_purple_text,
- R.style.Topeka_Purple),
+ R.color.theme_purple_accent, R.style.Topeka_Purple),
red(R.color.theme_red_primary, R.color.theme_red_primary_dark,
R.color.theme_red_background, R.color.theme_red_text,
- R.style.Topeka_Red),
+ R.color.theme_red_accent, R.style.Topeka_Red),
yellow(R.color.theme_yellow_primary, R.color.theme_yellow_primary_dark,
R.color.theme_yellow_background, R.color.theme_yellow_text,
- R.style.Topeka_Yellow);
+ R.color.theme_yellow_accent, R.style.Topeka_Yellow);
private final int mColorPrimaryId;
private final int mWindowBackgroundColorId;
private final int mColorPrimaryDarkId;
private final int mTextColorPrimaryId;
+ private final int mAccentColorId;
private final int mStyleId;
Theme(final int colorPrimaryId, final int colorPrimaryDarkId,
- final int windowBackgroundColorId, final int textColorPrimaryId,
- final int styleId) {
+ final int windowBackgroundColorId, final int textColorPrimaryId,
+ final int accentColorId, final int styleId) {
mColorPrimaryId = colorPrimaryId;
mWindowBackgroundColorId = windowBackgroundColorId;
mColorPrimaryDarkId = colorPrimaryDarkId;
mTextColorPrimaryId = textColorPrimaryId;
+ mAccentColorId = accentColorId;
mStyleId = styleId;
}
@@ -81,6 +83,11 @@ public int getPrimaryColor() {
return mColorPrimaryId;
}
+ @ColorRes
+ public int getAccentColor() {
+ return mAccentColorId;
+ }
+
@ColorRes
public int getPrimaryDarkColor() {
return mColorPrimaryDarkId;
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 208574ef..4b412643 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
@@ -18,9 +18,13 @@
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
+import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
import android.util.AttributeSet;
@@ -28,6 +32,7 @@
import android.widget.ImageView;
import com.google.samples.apps.topeka.R;
+import com.google.samples.apps.topeka.helper.ApiLevelHelper;
import com.google.samples.apps.topeka.widget.outlineprovider.RoundOutlineProvider;
/**
@@ -47,7 +52,6 @@ public AvatarView(Context context, AttributeSet attrs) {
public AvatarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- setClipToOutline(true);
}
@Override
@@ -66,6 +70,30 @@ public void toggle() {
setChecked(!mChecked);
}
+ /**
+ * Set the image for this avatar. Will be used to create a round version of this avatar.
+ *
+ * @param resId The image's resource id.
+ */
+ public void setAvatar(@DrawableRes int resId) {
+ if (ApiLevelHelper.isAtLeast(Build.VERSION_CODES.LOLLIPOP)) {
+ setClipToOutline(true);
+ setImageResource(resId);
+ } else {
+ setAvatarPreLollipop(resId);
+ }
+ }
+
+ private void setAvatarPreLollipop(@DrawableRes int resId) {
+ Drawable drawable = ResourcesCompat.getDrawable(getResources(), resId,
+ getContext().getTheme());
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+ RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create(getResources(),
+ bitmapDrawable.getBitmap());
+ roundedDrawable.setCircular(true);
+ setImageDrawable(roundedDrawable);
+ }
+
@Override
protected void onDraw(@NonNull Canvas canvas) {
super.onDraw(canvas);
@@ -79,6 +107,9 @@ protected void onDraw(@NonNull Canvas canvas) {
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
+ if (ApiLevelHelper.isLowerThan(Build.VERSION_CODES.LOLLIPOP)) {
+ return;
+ }
if (w > 0 && h > 0) {
setOutlineProvider(new RoundOutlineProvider(Math.min(w, h)));
}
diff --git a/app/src/main/java/com/google/samples/apps/topeka/widget/outlineprovider/RoundOutlineProvider.java b/app/src/main/java/com/google/samples/apps/topeka/widget/outlineprovider/RoundOutlineProvider.java
index 6cd178b7..7cfac468 100644
--- a/app/src/main/java/com/google/samples/apps/topeka/widget/outlineprovider/RoundOutlineProvider.java
+++ b/app/src/main/java/com/google/samples/apps/topeka/widget/outlineprovider/RoundOutlineProvider.java
@@ -16,13 +16,16 @@
package com.google.samples.apps.topeka.widget.outlineprovider;
+import android.annotation.TargetApi;
import android.graphics.Outline;
+import android.os.Build;
import android.view.View;
import android.view.ViewOutlineProvider;
/**
* Creates round outlines for views.
*/
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class RoundOutlineProvider extends ViewOutlineProvider {
private final int mSize;
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 5f0bf034..dfdd1d3c 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
@@ -16,23 +16,26 @@
package com.google.samples.apps.topeka.widget.quiz;
+import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
import android.os.Bundle;
+import android.os.Handler;
import android.support.annotation.ColorInt;
import android.support.annotation.DimenRes;
import android.support.v4.content.ContextCompat;
-import android.support.v4.view.ViewCompat;
+import android.support.v4.view.MarginLayoutParamsCompat;
+import android.support.v4.view.animation.LinearOutSlowInInterpolator;
import android.util.IntProperty;
import android.util.Property;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
@@ -40,6 +43,7 @@
import com.google.samples.apps.topeka.R;
import com.google.samples.apps.topeka.activity.QuizActivity;
+import com.google.samples.apps.topeka.helper.ApiLevelHelper;
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.CheckableFab;
@@ -56,66 +60,65 @@
*
The type of {@link com.google.samples.apps.topeka.model.quiz.Quiz} you want to - * display. + * display. */ public abstract class AbsQuizViewextends FrameLayout { - /** Property for animating the foreground color */ - public static final PropertyFOREGROUND_COLOR = - new IntProperty diff --git a/app/src/main/res/layout/activity_category_selection.xml b/app/src/main/res/layout/activity_category_selection.xml index b13c4d61..c5806842 100644 --- a/app/src/main/res/layout/activity_category_selection.xml +++ b/app/src/main/res/layout/activity_category_selection.xml @@ -33,6 +33,7 @@ android:layout_width="@dimen/size_avatar_toolbar" android:layout_height="@dimen/size_avatar_toolbar" android:layout_marginEnd="@dimen/spacing_double" + android:layout_marginRight="@dimen/spacing_double" android:transitionName="@string/transition_avatar" />("foregroundColor") { + private static final int ANSWER_HIDE_DELAY = 500; + private static final int FOREGROUND_COLOR_CHANGE_DELAY = 750; + protected final int mMinHeightTouchTarget; + private final int mSpacingDouble; + private final LayoutInflater mLayoutInflater; + private final Category mCategory; + private final Q mQuiz; + private Interpolator mLinearOutSlowInInterpolator; + private boolean mAnswered; + private TextView mQuestionView; + private CheckableFab mSubmitAnswer; + private Handler mHandler; + private Runnable mHideFabRunnable; + private Runnable mMoveOffScreenRunnable; + + private static final Property FOREGROUND_COLOR = + new IntProperty ("foregroundColor") { @Override - public void setValue(FrameLayout object, int value) { - if (object.getForeground() instanceof ColorDrawable) { - ((ColorDrawable) object.getForeground()).setColor(value); + public void setValue(AbsQuizView layout, int value) { + if (layout.getForeground() instanceof ColorDrawable) { + ((ColorDrawable) layout.getForeground().mutate()).setColor(value); } else { - object.setForeground(new ColorDrawable(value)); + layout.setForeground(new ColorDrawable(value)); } } @Override - public Integer get(FrameLayout object) { - return ((ColorDrawable) object.getForeground()).getColor(); + public Integer get(AbsQuizView layout) { + if (layout.getForeground() instanceof ColorDrawable) { + return ((ColorDrawable) layout.getForeground()).getColor(); + } else { + return Color.TRANSPARENT; + } } }; - protected final int mMinHeightTouchTarget; - private final int mSpacingDouble; - private final LayoutInflater mLayoutInflater; - private final Category mCategory; - private final Q mQuiz; - private final Interpolator mFastOutSlowInInterpolator; - private final Interpolator mLinearOutSlowInInterpolator; - private final int mIconAnimationDuration; - private final int mScaleAnimationDuration; - private boolean mAnswered; - private TextView mQuestionView; - private CheckableFab mSubmitAnswer; - /** * Enables creation of views for quizzes. * - * @param context The context for this view. + * @param context The context for this view. * @param category The {@link Category} this view is running in. - * @param quiz The actual {@link Quiz} that is going to be displayed. + * @param quiz The actual {@link Quiz} that is going to be displayed. */ public AbsQuizView(Context context, Category category, Q quiz) { super(context); mQuiz = quiz; mCategory = category; mSpacingDouble = getResources().getDimensionPixelSize(R.dimen.spacing_double); - mSubmitAnswer = getSubmitButton(context); mLayoutInflater = LayoutInflater.from(context); + mSubmitAnswer = getSubmitButton(); mMinHeightTouchTarget = getResources() .getDimensionPixelSize(R.dimen.min_height_touch_target); - //noinspection ResourceType - mFastOutSlowInInterpolator = AnimationUtils - .loadInterpolator(getContext(), android.R.interpolator.fast_out_slow_in); - //noinspection ResourceType - mLinearOutSlowInInterpolator = AnimationUtils - .loadInterpolator(getContext(), android.R.interpolator.linear_out_slow_in); - mIconAnimationDuration = 300; - mScaleAnimationDuration = 200; + mLinearOutSlowInInterpolator = new LinearOutSlowInInterpolator(); + mHandler = new Handler(); setId(quiz.getId()); setUpQuestionView(); @@ -180,17 +183,19 @@ private void addFloatingActionButton() { bottomOfQuestionView - halfAFab, //top 0, // right mSpacingDouble); // bottom - fabLayoutParams.setMarginEnd(mSpacingDouble); + MarginLayoutParamsCompat.setMarginEnd(fabLayoutParams, mSpacingDouble); + if (ApiLevelHelper.isLowerThan(Build.VERSION_CODES.LOLLIPOP)) { + // Account for the fab's emulated shadow. + fabLayoutParams.topMargin -= (mSubmitAnswer.getPaddingTop() / 2); + } addView(mSubmitAnswer, fabLayoutParams); } - private CheckableFab getSubmitButton(Context context) { + private CheckableFab getSubmitButton() { if (null == mSubmitAnswer) { - mSubmitAnswer = new CheckableFab(context); - mSubmitAnswer.setId(R.id.submitAnswer); - mSubmitAnswer.setVisibility(GONE); - mSubmitAnswer.setScaleY(0); - mSubmitAnswer.setScaleX(0); + mSubmitAnswer = (CheckableFab) getLayoutInflater() + .inflate(R.layout.answer_submit, this, false); + mSubmitAnswer.hide(); mSubmitAnswer.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -254,15 +259,11 @@ protected boolean isAnswered() { */ protected void allowAnswer(final boolean answered) { if (null != mSubmitAnswer) { - final float targetScale = answered ? 1f : 0f; if (answered) { - mSubmitAnswer.setVisibility(View.VISIBLE); + mSubmitAnswer.show(); + } else { + mSubmitAnswer.hide(); } - ViewCompat.animate(mSubmitAnswer) - .scaleX(targetScale) - .scaleY(targetScale) - .setInterpolator(mFastOutSlowInInterpolator) - .start(); mAnswered = answered; } } @@ -284,7 +285,6 @@ protected void submitAnswer() { submitAnswer(findViewById(R.id.submitAnswer)); } - @SuppressWarnings("UnusedParameters") private void submitAnswer(final View v) { final boolean answerCorrect = isAnswerCorrect(); @@ -298,14 +298,11 @@ private void submitAnswer(final View v) { * @param answerCorrect true
if the answer was correct, elsefalse
. */ private void performScoreAnimation(final boolean answerCorrect) { - - mSubmitAnswer.setChecked(answerCorrect); - + ((QuizActivity) getContext()).lockIdlingResource(); // Decide which background color to use. final int backgroundColor = ContextCompat.getColor(getContext(), answerCorrect ? R.color.green : R.color.red); - mSubmitAnswer.setBackgroundTintList(ColorStateList.valueOf(backgroundColor)); - hideFab(); + adjustFab(answerCorrect, backgroundColor); resizeView(); moveViewOffScreen(answerCorrect); // Animate the foreground color to match the background color. @@ -313,58 +310,67 @@ private void performScoreAnimation(final boolean answerCorrect) { animateForegroundColor(backgroundColor); } - private void hideFab() { - ViewCompat.animate(mSubmitAnswer) - .setDuration(mScaleAnimationDuration) - .setStartDelay(mIconAnimationDuration * 2) - .scaleX(0f) - .scaleY(0f) - .setInterpolator(mLinearOutSlowInInterpolator) - .start(); + private void adjustFab(boolean answerCorrect, int backgroundColor) { + mSubmitAnswer.setChecked(answerCorrect); + mSubmitAnswer.setBackgroundTintList(ColorStateList.valueOf(backgroundColor)); + mHideFabRunnable = new Runnable() { + @Override + public void run() { + mSubmitAnswer.hide(); + } + }; + mHandler.postDelayed(mHideFabRunnable, ANSWER_HIDE_DELAY); } private void resizeView() { final float widthHeightRatio = (float) getHeight() / (float) getWidth(); - // Animate X and Y scaling separately to allow different start delays. - ViewCompat.animate(this) - .scaleY(.5f / widthHeightRatio) - .setDuration(300) - .setStartDelay(750) - .start(); - ViewCompat.animate(this) - .scaleX(.5f) - .setDuration(300) - .setStartDelay(800) - .start(); + // object animators for x and y with different durations and then run them independently + resizeViewProperty(View.SCALE_X, .5f, 200); + resizeViewProperty(View.SCALE_Y, .5f / widthHeightRatio, 250); } - private void animateForegroundColor(@ColorInt 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 resizeViewProperty(Propertyproperty, + float targetScale, int durationOffset) { + ObjectAnimator animator = ObjectAnimator.ofFloat(this, property, + 1f, targetScale); + animator.setInterpolator(mLinearOutSlowInInterpolator); + animator.setStartDelay(FOREGROUND_COLOR_CHANGE_DELAY + durationOffset); + animator.start(); + } + + @Override + protected void onDetachedFromWindow() { + if (mHideFabRunnable != null) { + mHandler.removeCallbacks(mHideFabRunnable); + } + if (mMoveOffScreenRunnable != null) { + mHandler.removeCallbacks(mMoveOffScreenRunnable); + } + super.onDetachedFromWindow(); + } + + private void animateForegroundColor(@ColorInt final int targetColor) { + ObjectAnimator animator = ObjectAnimator.ofInt(this, FOREGROUND_COLOR, + Color.TRANSPARENT, targetColor); + animator.setEvaluator(new ArgbEvaluator()); + animator.setStartDelay(FOREGROUND_COLOR_CHANGE_DELAY); + animator.start(); } private void moveViewOffScreen(final boolean answerCorrect) { - // Animate the current view off the screen. - ViewCompat.animate(this) - .setDuration(200) - .setStartDelay(1200) - .setInterpolator(mLinearOutSlowInInterpolator) - .withEndAction(new Runnable() { - @Override - public void run() { - mCategory.setScore(getQuiz(), answerCorrect); - if (getContext() instanceof QuizActivity) { - ((QuizActivity) getContext()).proceed(); - } - } - }) - .start(); + // Move the current view off the screen. + mMoveOffScreenRunnable = new Runnable() { + @Override + public void run() { + mCategory.setScore(getQuiz(), answerCorrect); + if (getContext() instanceof QuizActivity) { + ((QuizActivity) getContext()).proceed(); + } + } + }; + mHandler.postDelayed(mMoveOffScreenRunnable, + FOREGROUND_COLOR_CHANGE_DELAY * 2); } private void setMinHeightInternal(View view, @DimenRes int resId) { diff --git a/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/FillTwoBlanksQuizView.java b/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/FillTwoBlanksQuizView.java index d7780848..0d2dac79 100644 --- a/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/FillTwoBlanksQuizView.java +++ b/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/FillTwoBlanksQuizView.java @@ -24,6 +24,7 @@ import android.widget.EditText; import android.widget.LinearLayout; +import com.google.samples.apps.topeka.R; import com.google.samples.apps.topeka.model.Category; import com.google.samples.apps.topeka.model.quiz.FillTwoBlanksQuiz; @@ -48,6 +49,7 @@ protected View createQuizContentView() { mAnswerOne = createEditText(); mAnswerOne.setImeOptions(EditorInfo.IME_ACTION_NEXT); mAnswerTwo = createEditText(); + mAnswerTwo.setId(R.id.quiz_edit_text_two); addEditText(layout, mAnswerOne); addEditText(layout, mAnswerTwo); return layout; diff --git a/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/SelectItemQuizView.java b/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/SelectItemQuizView.java index 74095e96..58ad1f3b 100644 --- a/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/SelectItemQuizView.java +++ b/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/SelectItemQuizView.java @@ -47,12 +47,13 @@ public SelectItemQuizView(Context context, Category category, SelectItemQuiz qui @Override protected View createQuizContentView() { - mListView = new ListView(getContext()); + Context context = getContext(); + mListView = new ListView(context); mListView.setDivider(null); mListView.setSelector(R.drawable.selector_button); mListView.setAdapter( new OptionsQuizAdapter(getQuiz().getOptions(), R.layout.item_answer_start, - getContext(), true)); + context, true)); mListView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE); mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override diff --git a/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/ToggleTranslateQuizView.java b/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/ToggleTranslateQuizView.java index 35953117..26d44d18 100644 --- a/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/ToggleTranslateQuizView.java +++ b/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/ToggleTranslateQuizView.java @@ -43,7 +43,11 @@ public class ToggleTranslateQuizView extends AbsQuizView { public ToggleTranslateQuizView(Context context, Category category, ToggleTranslateQuiz quiz) { super(context, category, quiz); - mAnswers = new boolean[quiz.getOptions().length]; + initAnswerSpace(); + } + + private void initAnswerSpace() { + mAnswers = new boolean[getQuiz().getOptions().length]; } @Override @@ -89,6 +93,7 @@ public void setUserInput(Bundle savedInput) { } mAnswers = savedInput.getBooleanArray(KEY_ANSWERS); if (mAnswers == null) { + initAnswerSpace(); return; } ListAdapter adapter = mListView.getAdapter(); diff --git a/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/TrueFalseQuizView.java b/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/TrueFalseQuizView.java index 05079395..615dfd6b 100644 --- a/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/TrueFalseQuizView.java +++ b/app/src/main/java/com/google/samples/apps/topeka/widget/quiz/TrueFalseQuizView.java @@ -56,10 +56,10 @@ protected View createQuizContentView() { @Override public void onClick(View v) { switch (v.getId()) { - case R.id.answerTrue: + case R.id.answer_true: mAnswer = true; break; - case R.id.answerFalse: + case R.id.answer_false: mAnswer = false; break; } @@ -67,9 +67,9 @@ public void onClick(View v) { } }; - mAnswerTrue = container.findViewById(R.id.answerTrue); + mAnswerTrue = container.findViewById(R.id.answer_true); mAnswerTrue.setOnClickListener(clickListener); - mAnswerFalse = container.findViewById(R.id.answerFalse); + mAnswerFalse = container.findViewById(R.id.answer_false); mAnswerFalse.setOnClickListener(clickListener); return container; } diff --git a/app/src/main/res/drawable-hdpi/ic_arrow_back_black.png b/app/src/main/res/drawable-hdpi/ic_arrow_back_black.png new file mode 100644 index 00000000..da807e99 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_arrow_back_black.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_check_black.png b/app/src/main/res/drawable-hdpi/ic_check_black.png new file mode 100644 index 00000000..e802d90a Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_check_black.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_close_black.png b/app/src/main/res/drawable-hdpi/ic_close_black.png new file mode 100644 index 00000000..1a9cd75a Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_close_black.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_play_arrow_black.png b/app/src/main/res/drawable-hdpi/ic_play_arrow_black.png new file mode 100644 index 00000000..e9c288c9 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_play_arrow_black.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_arrow_back_black.png b/app/src/main/res/drawable-mdpi/ic_arrow_back_black.png new file mode 100644 index 00000000..ad388309 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_arrow_back_black.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_check_black.png b/app/src/main/res/drawable-mdpi/ic_check_black.png new file mode 100644 index 00000000..1c14c9c4 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_check_black.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_close_black.png b/app/src/main/res/drawable-mdpi/ic_close_black.png new file mode 100644 index 00000000..40a1a84e Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_close_black.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_play_arrow_black.png b/app/src/main/res/drawable-mdpi/ic_play_arrow_black.png new file mode 100644 index 00000000..d78c57ba Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_play_arrow_black.png differ diff --git a/app/src/main/res/drawable-v21/ic_arrow_back.xml b/app/src/main/res/drawable-v21/ic_arrow_back.xml new file mode 100644 index 00000000..4bd48eaf --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_arrow_back.xml @@ -0,0 +1,25 @@ + + + + diff --git a/app/src/main/res/drawable-v21/ic_cross.xml b/app/src/main/res/drawable-v21/ic_cross.xml new file mode 100644 index 00000000..a5f0b16c --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_cross.xml @@ -0,0 +1,44 @@ + + ++ + + diff --git a/app/src/main/res/drawable-v21/ic_play.xml b/app/src/main/res/drawable-v21/ic_play.xml new file mode 100644 index 00000000..21fa3d07 --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_play.xml @@ -0,0 +1,25 @@ + + ++ + + ++ + + + + diff --git a/app/src/main/res/drawable-v21/ic_tick.xml b/app/src/main/res/drawable-v21/ic_tick.xml new file mode 100644 index 00000000..30d2ef97 --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_tick.xml @@ -0,0 +1,44 @@ + + ++ + + diff --git a/app/src/main/res/drawable/ripple.xml b/app/src/main/res/drawable-v21/ripple.xml similarity index 100% rename from app/src/main/res/drawable/ripple.xml rename to app/src/main/res/drawable-v21/ripple.xml diff --git a/app/src/main/res/drawable-v21/selector_button.xml b/app/src/main/res/drawable-v21/selector_button.xml new file mode 100644 index 00000000..c70241a1 --- /dev/null +++ b/app/src/main/res/drawable-v21/selector_button.xml @@ -0,0 +1,29 @@ + + ++ + + ++ + + + + diff --git a/app/src/main/res/drawable-v21/selector_categories.xml b/app/src/main/res/drawable-v21/selector_categories.xml new file mode 100644 index 00000000..0c85908b --- /dev/null +++ b/app/src/main/res/drawable-v21/selector_categories.xml @@ -0,0 +1,24 @@ + + +- +
++ +- +
++ - +
++ + diff --git a/app/src/main/res/drawable-v21/selector_checkable.xml b/app/src/main/res/drawable-v21/selector_checkable.xml new file mode 100644 index 00000000..d25b5d5e --- /dev/null +++ b/app/src/main/res/drawable-v21/selector_checkable.xml @@ -0,0 +1,29 @@ + + +- +
++ ++ + diff --git a/app/src/main/res/drawable-v21/selector_false.xml b/app/src/main/res/drawable-v21/selector_false.xml new file mode 100644 index 00000000..4d52e228 --- /dev/null +++ b/app/src/main/res/drawable-v21/selector_false.xml @@ -0,0 +1,29 @@ + + +- +
++ +- +
++ - +
++ + diff --git a/app/src/main/res/drawable-v21/selector_true.xml b/app/src/main/res/drawable-v21/selector_true.xml new file mode 100644 index 00000000..9c01f078 --- /dev/null +++ b/app/src/main/res/drawable-v21/selector_true.xml @@ -0,0 +1,31 @@ + + +- +
++ +- +
++ - +
++ + diff --git a/app/src/main/res/drawable-xhdpi/ic_arrow_back_black.png b/app/src/main/res/drawable-xhdpi/ic_arrow_back_black.png new file mode 100644 index 00000000..68427253 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_arrow_back_black.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_check_black.png b/app/src/main/res/drawable-xhdpi/ic_check_black.png new file mode 100644 index 00000000..64a4944f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_check_black.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_close_black.png b/app/src/main/res/drawable-xhdpi/ic_close_black.png new file mode 100644 index 00000000..6bc43729 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_close_black.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_play_arrow_black.png b/app/src/main/res/drawable-xhdpi/ic_play_arrow_black.png new file mode 100644 index 00000000..f208795f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_play_arrow_black.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_arrow_back_black.png b/app/src/main/res/drawable-xxhdpi/ic_arrow_back_black.png new file mode 100644 index 00000000..fa432c23 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_arrow_back_black.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_check_black.png b/app/src/main/res/drawable-xxhdpi/ic_check_black.png new file mode 100644 index 00000000..b26a2c05 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_check_black.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_close_black.png b/app/src/main/res/drawable-xxhdpi/ic_close_black.png new file mode 100644 index 00000000..51b4401c Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_close_black.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_play_arrow_black.png b/app/src/main/res/drawable-xxhdpi/ic_play_arrow_black.png new file mode 100644 index 00000000..5345ee3c Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_play_arrow_black.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_arrow_back_black.png b/app/src/main/res/drawable-xxxhdpi/ic_arrow_back_black.png new file mode 100644 index 00000000..fb5235fb Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_arrow_back_black.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_check_black.png b/app/src/main/res/drawable-xxxhdpi/ic_check_black.png new file mode 100644 index 00000000..2f6d6386 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_check_black.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_close_black.png b/app/src/main/res/drawable-xxxhdpi/ic_close_black.png new file mode 100644 index 00000000..df42feec Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_close_black.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_play_arrow_black.png b/app/src/main/res/drawable-xxxhdpi/ic_play_arrow_black.png new file mode 100644 index 00000000..d12d4956 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_play_arrow_black.png differ diff --git a/app/src/main/res/drawable/ic_arrow_back.xml b/app/src/main/res/drawable/ic_arrow_back.xml index da7882e3..8c952697 100644 --- a/app/src/main/res/drawable/ic_arrow_back.xml +++ b/app/src/main/res/drawable/ic_arrow_back.xml @@ -1,3 +1,4 @@ + - -- +
++ +- +
++ - +
++ - +- diff --git a/app/src/main/res/drawable/ic_cross.xml b/app/src/main/res/drawable/ic_cross.xml index cfbfe6eb..6a66b9fa 100644 --- a/app/src/main/res/drawable/ic_cross.xml +++ b/app/src/main/res/drawable/ic_cross.xml @@ -1,3 +1,4 @@ + - - - - +- - - -- - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_play.xml b/app/src/main/res/drawable/ic_play.xml index e7aeaa62..ffa671f6 100644 --- a/app/src/main/res/drawable/ic_play.xml +++ b/app/src/main/res/drawable/ic_play.xml @@ -1,3 +1,4 @@ + - - - + +- diff --git a/app/src/main/res/drawable/ic_tick.xml b/app/src/main/res/drawable/ic_tick.xml index 79c2833b..dbcfacf6 100644 --- a/app/src/main/res/drawable/ic_tick.xml +++ b/app/src/main/res/drawable/ic_tick.xml @@ -1,3 +1,4 @@ + - - - - + +- - - -- - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_avatar.xml b/app/src/main/res/drawable/selector_avatar.xml index e62a908f..38992b3d 100644 --- a/app/src/main/res/drawable/selector_avatar.xml +++ b/app/src/main/res/drawable/selector_avatar.xml @@ -19,4 +19,5 @@ + diff --git a/app/src/main/res/drawable/selector_button.xml b/app/src/main/res/drawable/selector_button.xml index c70241a1..a54e379f 100644 --- a/app/src/main/res/drawable/selector_button.xml +++ b/app/src/main/res/drawable/selector_button.xml @@ -14,16 +14,11 @@ ~ limitations under the License. --> - + + diff --git a/app/src/main/res/drawable/selector_categories.xml b/app/src/main/res/drawable/selector_categories.xml new file mode 100644 index 00000000..d388107b --- /dev/null +++ b/app/src/main/res/drawable/selector_categories.xml @@ -0,0 +1,19 @@ + + + ++ - +
+ - -
-- +- -
-- - -
-- \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_checkable.xml b/app/src/main/res/drawable/selector_checkable.xml index d25b5d5e..fac818c8 100644 --- a/app/src/main/res/drawable/selector_checkable.xml +++ b/app/src/main/res/drawable/selector_checkable.xml @@ -13,17 +13,8 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - - - + diff --git a/app/src/main/res/drawable/selector_false.xml b/app/src/main/res/drawable/selector_false.xml index 85d31248..ad14966e 100644 --- a/app/src/main/res/drawable/selector_false.xml +++ b/app/src/main/res/drawable/selector_false.xml @@ -13,19 +13,11 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - -- -
- +- -
-- - -
-- + - +
-- +- -
- +- -
-- - -
-- + - +
-- +
+ diff --git a/app/src/main/res/drawable/selector_list.xml b/app/src/main/res/drawable/selector_list.xml new file mode 100644 index 00000000..ba4677a9 --- /dev/null +++ b/app/src/main/res/drawable/selector_list.xml @@ -0,0 +1,19 @@ + + ++ + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_true.xml b/app/src/main/res/drawable/selector_true.xml index 9c01f078..a4c2c908 100644 --- a/app/src/main/res/drawable/selector_true.xml +++ b/app/src/main/res/drawable/selector_true.xml @@ -14,18 +14,11 @@ ~ limitations under the License. --> -- +
- +- -
- +- -
-- - -
-- + - +
-- +
+ diff --git a/app/src/main/res/layout-land/fragment_sign_in.xml b/app/src/main/res/layout-land/fragment_sign_in.xml index df400b30..6eb47355 100644 --- a/app/src/main/res/layout-land/fragment_sign_in.xml +++ b/app/src/main/res/layout-land/fragment_sign_in.xml @@ -32,10 +32,6 @@ android:layout_width="match_parent" android:layout_height="match_parent"> -+ - + + + - - - - diff --git a/app/src/main/res/layout/answer_submit.xml b/app/src/main/res/layout/answer_submit.xml new file mode 100644 index 00000000..08b1fa61 --- /dev/null +++ b/app/src/main/res/layout/answer_submit.xml @@ -0,0 +1,24 @@ + + + +- - + + + + @@ -78,4 +69,16 @@ android:visibility="invisible" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fab_done.xml b/app/src/main/res/layout/fab_done.xml index 04f262e7..1ea162df 100644 --- a/app/src/main/res/layout/fab_done.xml +++ b/app/src/main/res/layout/fab_done.xml @@ -18,10 +18,12 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/done" - android:layout_width="@dimen/size_fab" - android:layout_height="@dimen/size_fab" + app:fabSize="normal" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_marginBottom="@dimen/spacing_double" android:layout_marginEnd="@dimen/spacing_double" + android:layout_marginRight="@dimen/spacing_double" android:src="@drawable/ic_tick" app:backgroundTint="@color/topeka_primary" /> diff --git a/app/src/main/res/layout/fragment_categories.xml b/app/src/main/res/layout/fragment_categories.xml index 16b3e3a3..584bb927 100644 --- a/app/src/main/res/layout/fragment_categories.xml +++ b/app/src/main/res/layout/fragment_categories.xml @@ -24,7 +24,7 @@ android:clipToPadding="false" android:drawSelectorOnTop="true" android:horizontalSpacing="@dimen/spacing_micro" - android:listSelector="@drawable/ripple" + android:listSelector="@drawable/selector_categories" android:numColumns="auto_fit" android:padding="@dimen/spacing_micro" android:scrollbarStyle="outsideOverlay" diff --git a/app/src/main/res/layout/fragment_quiz.xml b/app/src/main/res/layout/fragment_quiz.xml index 3987bc85..168c8ccb 100644 --- a/app/src/main/res/layout/fragment_quiz.xml +++ b/app/src/main/res/layout/fragment_quiz.xml @@ -38,7 +38,7 @@ android:id="@+id/progress_toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?android:colorPrimary" + android:background="?colorPrimary" android:elevation="@dimen/elevation_header"> + android:layout_marginEnd="@dimen/spacing_double" + android:layout_marginRight="@dimen/spacing_double" + android:scaleX="0" + android:scaleY="0"/> - - + diff --git a/app/src/main/res/layout/item_scorecard.xml b/app/src/main/res/layout/item_scorecard.xml index fcc3db5a..e6d876f4 100644 --- a/app/src/main/res/layout/item_scorecard.xml +++ b/app/src/main/res/layout/item_scorecard.xml @@ -15,20 +15,21 @@ --> + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@null" + android:orientation="horizontal" + android:paddingBottom="@dimen/spacing_normal" + android:paddingTop="@dimen/spacing_normal" + tools:ignore="Overdraw"> \ No newline at end of file diff --git a/app/src/main/res/layout/quiz_radio_group_true_false.xml b/app/src/main/res/layout/quiz_radio_group_true_false.xml index 3b70fbbe..e5b852de 100644 --- a/app/src/main/res/layout/quiz_radio_group_true_false.xml +++ b/app/src/main/res/layout/quiz_radio_group_true_false.xml @@ -20,20 +20,22 @@ android:orientation="horizontal"> - + \ No newline at end of file diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml new file mode 100644 index 00000000..c0f2d5a0 --- /dev/null +++ b/app/src/main/res/values-v21/styles.xml @@ -0,0 +1,30 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index 1b8d8f63..f8bc9f76 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -19,4 +19,5 @@- +
- \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index db40b24a..2416129d 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -17,8 +17,7 @@
- + - - + + - - - @@ -116,7 +114,7 @@ diff --git a/build.gradle b/build.gradle index eb242d01..e82f2a81 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ buildscript { } task wrapper(type: Wrapper) { - gradleVersion = "2.4" + gradleVersion = "2.7" } allprojects { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index c97a8bdb..b5166dad 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 50f0706c..32b4e84b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Jun 10 13:27:32 BST 2015 +#Mon Sep 21 17:26:58 BST 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-all.zip diff --git a/screenrecord b/screenrecord new file mode 100644 index 00000000..3a121a3e Binary files /dev/null and b/screenrecord differ diff --git a/screenshots/categories.png b/screenshots/categories.png index a674a39f..ae6b0a28 100644 Binary files a/screenshots/categories.png and b/screenshots/categories.png differ diff --git a/screenshots/category_history.png b/screenshots/category_history.png index 8bf62d9a..7b212097 100644 Binary files a/screenshots/category_history.png and b/screenshots/category_history.png differ diff --git a/screenshots/quiz_shakespeare.png b/screenshots/quiz_shakespeare.png index 9fdc2e76..309b27e4 100644 Binary files a/screenshots/quiz_shakespeare.png and b/screenshots/quiz_shakespeare.png differ- 96sp
-