diff --git a/app/build.gradle b/app/build.gradle index 694ec30d2..feb6756ce 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -58,8 +58,8 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_7 - targetCompatibility JavaVersion.VERSION_1_7 + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } } @@ -69,7 +69,7 @@ repositories { } dependencies { - implementation 'com.android.support.constraint:constraint-layout:1.1.0-beta3' + implementation 'com.android.support.constraint:constraint-layout:1.1.0-beta4' implementation "com.android.support:customtabs:${versions.supportLibrary}" implementation "com.android.support:design:${versions.supportLibrary}" implementation "com.android.support:palette-v7:${versions.supportLibrary}" diff --git a/app/src/main/java/io/plaidapp/ui/ShareDribbbleImageTask.java b/app/src/main/java/io/plaidapp/ui/ShareDribbbleImageTask.java index cbd06feb2..c46dcfcb7 100644 --- a/app/src/main/java/io/plaidapp/ui/ShareDribbbleImageTask.java +++ b/app/src/main/java/io/plaidapp/ui/ShareDribbbleImageTask.java @@ -78,14 +78,7 @@ protected void onPostExecute(File result) { } private String getShareText() { - return new StringBuilder() - .append("“") - .append(shot.title) - .append("” by ") - .append(shot.user.name) - .append("\n") - .append(shot.url) - .toString(); + return "“" + shot.title + "” by " + shot.user.name + "\n" + shot.url; } private String getImageMimeType(@NonNull String fileName) { diff --git a/app/src/main/java/io/plaidapp/ui/transitions/MorphDialogToFab.java b/app/src/main/java/io/plaidapp/ui/transitions/MorphDialogToFab.java index b34d5c8e4..4946e5ca9 100644 --- a/app/src/main/java/io/plaidapp/ui/transitions/MorphDialogToFab.java +++ b/app/src/main/java/io/plaidapp/ui/transitions/MorphDialogToFab.java @@ -124,8 +124,8 @@ public Animator createAnimator(final ViewGroup sceneRoot, MorphDrawable background = new MorphDrawable(startColor, startCornerRadius); endValues.view.setBackground(background); - Animator color = ObjectAnimator.ofArgb(background, background.COLOR, endColor); - Animator corners = ObjectAnimator.ofFloat(background, background.CORNER_RADIUS, + Animator color = ObjectAnimator.ofArgb(background, MorphDrawable.COLOR, endColor); + Animator corners = ObjectAnimator.ofFloat(background, MorphDrawable.CORNER_RADIUS, endCornerRadius); // hide child views (offset down & fade out) diff --git a/app/src/main/java/io/plaidapp/ui/widget/CheckableImageButton.java b/app/src/main/java/io/plaidapp/ui/widget/CheckableImageButton.java index 0accb1966..d15b47115 100644 --- a/app/src/main/java/io/plaidapp/ui/widget/CheckableImageButton.java +++ b/app/src/main/java/io/plaidapp/ui/widget/CheckableImageButton.java @@ -17,6 +17,7 @@ package io.plaidapp.ui.widget; import android.content.Context; +import android.support.v7.widget.AppCompatImageButton; import android.util.AttributeSet; import android.view.SoundEffectConstants; import android.widget.Checkable; @@ -25,7 +26,7 @@ /** * An extension to {@link ImageButton} which implements the {@link Checkable} interface. */ -public class CheckableImageButton extends ImageButton implements Checkable { +public class CheckableImageButton extends AppCompatImageButton implements Checkable { private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked}; diff --git a/app/src/main/java/io/plaidapp/ui/widget/CutoutTextView.java b/app/src/main/java/io/plaidapp/ui/widget/CutoutTextView.java index db13eace4..7d303b8ee 100644 --- a/app/src/main/java/io/plaidapp/ui/widget/CutoutTextView.java +++ b/app/src/main/java/io/plaidapp/ui/widget/CutoutTextView.java @@ -45,7 +45,6 @@ public class CutoutTextView extends View { private Bitmap cutout; private int foregroundColor = Color.MAGENTA; private String text; - private float textSize; private float textY; private float textX; private float maxTextSize; @@ -86,8 +85,8 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) { private void calculateTextPosition() { float targetWidth = getWidth() / PHI; - textSize = ViewUtils.getSingleLineTextSize(text, textPaint, targetWidth, 0f, maxTextSize, - 0.5f, getResources().getDisplayMetrics()); + float textSize = ViewUtils.getSingleLineTextSize( + text, textPaint, targetWidth, 0f, maxTextSize, 0.5f, getResources().getDisplayMetrics()); textPaint.setTextSize(textSize); // measuring text is fun :] see: https://chris.banes.me/2014/03/27/measuring-text/ diff --git a/app/src/main/java/io/plaidapp/ui/widget/DynamicTextView.java b/app/src/main/java/io/plaidapp/ui/widget/DynamicTextView.java deleted file mode 100644 index be7adc3fd..000000000 --- a/app/src/main/java/io/plaidapp/ui/widget/DynamicTextView.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * 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 io.plaidapp.ui.widget; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Color; -import android.graphics.Typeface; -import android.text.Layout; -import android.text.StaticLayout; -import android.text.TextPaint; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.widget.TextView; - -import io.plaidapp.R; - -/** - * TODO: document your custom view class. - */ -public class DynamicTextView extends TextView { - - private static MaterialTypeStyle[] mStyles = { - new MaterialTypeStyle(112, "sans-serif-light", 0x8a), /* Display 4 */ - new MaterialTypeStyle(56, "sans-serif", 0x8a), /* Display 3 */ - new MaterialTypeStyle(45, "sans-serif", 0x8a), /* Display 2 */ - new MaterialTypeStyle(34, "sans-serif", 0x8a), /* Display 1 */ - new MaterialTypeStyle(24, "sans-serif", 0xde), /* Headline */ - new MaterialTypeStyle(20, "sans-serif-medium", 0xde) /* Title */ - }; - private boolean mSnapToMaterialScale; - private int mMinTextSize; - private int mMaxTextSize; - private float scaledDensity; - private boolean mCalculated = false; - - public DynamicTextView(Context context) { - super(context); - init(null, 0); - } - - public DynamicTextView(Context context, AttributeSet attrs) { - super(context, attrs); - init(attrs, 0); - } - - public DynamicTextView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(attrs, defStyle); - } - - private void init(AttributeSet attrs, int defStyle) { - scaledDensity = getContext().getResources().getDisplayMetrics().scaledDensity; - // Load attributes - final TypedArray a = getContext().obtainStyledAttributes( - attrs, R.styleable.DynamicTextView, defStyle, 0); - - mSnapToMaterialScale = a.getBoolean(R.styleable.DynamicTextView_snapToMaterialScale, true); - mMinTextSize = a.getDimensionPixelSize( - R.styleable.DynamicTextView_minTextSize, - (int) (20 * scaledDensity)); - - mMaxTextSize = a.getDimensionPixelSize( - R.styleable.DynamicTextView_maxTextSize, - (int) (112 * scaledDensity)); - - a.recycle(); - } - - private void fitText() { - - // different methods for achieving this depending on whether we are snapping to the material - // scale, and if multiple lines are allowed. 4 method for the permutations of this. - - if (mSnapToMaterialScale && getMaxLines() == 1) { - // technically we could use the multi line algorithm here but this is more efficient - fitSnappedSingleLine(); - } else if (mSnapToMaterialScale) { - fitSnappedMultiLine(); - } else if (!mSnapToMaterialScale && getMaxLines() == 1) { - fitSingleLine(); - } else if (!mSnapToMaterialScale) { - fitMultiline(); - } - } - - private void fitSnappedMultiLine() { - int targetWidth = getWidth() - getPaddingLeft() - getPaddingRight(); - int targetHeight = getHeight() - getPaddingTop() - getPaddingBottom(); - if (targetWidth > 0 && targetHeight > 0) { - int style = 0; - MaterialTypeStyle currentStyle = mStyles[style]; - TextPaint paint = getPaint(); - StaticLayout staticLayout = null; - int currentHeight = Integer.MAX_VALUE; - int lines = 0; - boolean maxLinesSet = getMaxLines() != Integer.MAX_VALUE; - - while ((currentHeight > targetHeight || (maxLinesSet && lines > getMaxLines())) - && style <= mStyles.length - 1 - && currentStyle.size * scaledDensity >= mMinTextSize - && currentStyle.size * scaledDensity <= mMaxTextSize) { - currentStyle = mStyles[style]; - paint.setTextSize(currentStyle.size * scaledDensity); - paint.setTypeface(Typeface.create(currentStyle.fontFamily, Typeface.NORMAL)); - staticLayout = new StaticLayout(getText(), paint, targetWidth, Layout.Alignment - .ALIGN_NORMAL, 1.0f, 0.0f, true); - currentHeight = staticLayout.getHeight(); - lines = staticLayout.getLineCount(); - style++; - } - super.setTextSize(TypedValue.COMPLEX_UNIT_SP, currentStyle.size); - setTypeface(Typeface.create(currentStyle.fontFamily, Typeface.NORMAL)); - - int currentColour = getCurrentTextColor(); - setTextColor(Color.argb(currentStyle.opacity, - Color.red(currentColour), - Color.green(currentColour), - Color.blue(currentColour))); - - if (style == mStyles.length) { - setEllipsize(TextUtils.TruncateAt.END); - } - if (currentStyle.size * scaledDensity < mMinTextSize) { - // wanted to make text smaller but hit min text size. Need to set max lines. - setMaxLines((int) Math.floor((((float) targetHeight / (float) currentHeight) * - lines))); - setEllipsize(TextUtils.TruncateAt.END); - } - setTextAlignment(TEXT_ALIGNMENT_TEXT_START); - mCalculated = true; - } - } - - private void fitSnappedSingleLine() { - int targetWidth = getWidth() - getPaddingLeft() - getPaddingRight(); - if (targetWidth > 0) { - int style = 0; - TextPaint paint = getPaint(); - final String text = getText().toString(); - MaterialTypeStyle currentStyle = null; - float currentWidth = Float.MAX_VALUE; - - while (currentWidth > targetWidth && style < mStyles.length) { - currentStyle = mStyles[style]; - paint.setTextSize(currentStyle.size * scaledDensity); - paint.setTypeface(Typeface.create(currentStyle.fontFamily, Typeface.NORMAL)); - currentWidth = paint.measureText(text); - style++; - } - setTextSize(TypedValue.COMPLEX_UNIT_SP, currentStyle.size); - setTypeface(Typeface.create(currentStyle.fontFamily, Typeface.NORMAL)); - - int currentColour = getCurrentTextColor(); - setTextColor(Color.argb(currentStyle.opacity, - Color.red(currentColour), - Color.green(currentColour), - Color.blue(currentColour))); - - if (style == mStyles.length) { - setEllipsize(TextUtils.TruncateAt.END); - } - mCalculated = true; - } - } - - private void fitMultiline() { - int targetWidth = getWidth() - getPaddingLeft() - getPaddingRight(); - int targetHeight = getHeight() - getPaddingTop() - getPaddingBottom(); - if (targetWidth > 0 && targetHeight > 0) { - int textSize = mMaxTextSize; - TextPaint paint = getPaint(); - paint.setTextSize(textSize); - StaticLayout staticLayout = new StaticLayout(getText(), paint, targetWidth, Layout - .Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true); - int currentHeight = staticLayout.getHeight(); - - while (currentHeight > targetHeight && textSize > mMinTextSize) { - textSize--; - paint.setTextSize(textSize); - staticLayout = new StaticLayout(getText(), paint, targetWidth, Layout.Alignment - .ALIGN_NORMAL, 1.0f, 0.0f, true); - currentHeight = staticLayout.getHeight(); - } - setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); - setTextAlignment(TEXT_ALIGNMENT_TEXT_START); - mCalculated = true; - } - } - - private void fitSingleLine() { - int targetWidth = getWidth() - getPaddingLeft() - getPaddingRight(); - if (targetWidth > 0) { - int textSize = mMaxTextSize; - TextPaint paint = getPaint(); - paint.setTextSize(textSize); - final String text = getText().toString(); - float currentWidth = paint.measureText(text); - - while (currentWidth > targetWidth && textSize > mMinTextSize) { - textSize--; - paint.setTextSize(textSize); - currentWidth = paint.measureText(text); - } - setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); - mCalculated = true; - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - if (!mCalculated) { - fitText(); - } - } - - public boolean isSnapToMaterialScale() { - return mSnapToMaterialScale; - } - - public void setSnapToMaterialScale(boolean snapToMaterialScale) { - this.mSnapToMaterialScale = snapToMaterialScale; - } - - public int getMinTextSize() { - return mMinTextSize; - } - - public void setMinTextSize(int minTextSize) { - this.mMinTextSize = minTextSize; - } - - public int getMaxTextSize() { - return mMaxTextSize; - } - - public void setMaxTextSize(int maxTextSize) { - this.mMaxTextSize = maxTextSize; - } - - private static class MaterialTypeStyle { - int size; - String fontFamily; - int opacity; - - MaterialTypeStyle(int size, String fontFamily, int opacity) { - this.size = size; - this.fontFamily = fontFamily; - this.opacity = opacity; - } - } -} diff --git a/app/src/main/java/io/plaidapp/ui/widget/ElasticDragDismissFrameLayout.java b/app/src/main/java/io/plaidapp/ui/widget/ElasticDragDismissFrameLayout.java index 7aeacd048..086b67b33 100644 --- a/app/src/main/java/io/plaidapp/ui/widget/ElasticDragDismissFrameLayout.java +++ b/app/src/main/java/io/plaidapp/ui/widget/ElasticDragDismissFrameLayout.java @@ -21,6 +21,7 @@ import android.content.res.TypedArray; import android.graphics.Color; import android.util.AttributeSet; +import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; @@ -50,6 +51,7 @@ public class ElasticDragDismissFrameLayout extends FrameLayout { private float totalDrag; private boolean draggingDown = false; private boolean draggingUp = false; + private int mLastActionEvent; private List callbacks; @@ -135,12 +137,25 @@ public void onNestedScroll(View target, int dxConsumed, int dyConsumed, dragScale(dyUnconsumed); } + @Override public boolean onInterceptTouchEvent(MotionEvent ev) { + mLastActionEvent = ev.getAction(); + return super.onInterceptTouchEvent(ev); + } + @Override public void onStopNestedScroll(View child) { if (Math.abs(totalDrag) >= dragDismissDistance) { dispatchDismissCallback(); } else { // settle back to natural position - animate() + if (mLastActionEvent == MotionEvent.ACTION_DOWN) { + // this is a 'defensive cleanup for new gestures', + // don't animate here + // see also https://github.com/nickbutcher/plaid/issues/185 + setTranslationY(0f); + setScaleX(1f); + setScaleY(1f); + } else { + animate() .translationY(0f) .scaleX(1f) .scaleY(1f) @@ -148,6 +163,7 @@ public void onStopNestedScroll(View child) { .setInterpolator(AnimUtils.getFastOutSlowInInterpolator(getContext())) .setListener(null) .start(); + } totalDrag = 0; draggingDown = draggingUp = false; dispatchDragCallback(0f, 0f, 0f, 0f); diff --git a/app/src/main/java/io/plaidapp/ui/widget/FABToggle.java b/app/src/main/java/io/plaidapp/ui/widget/FABToggle.java index 0903a4de4..ca4d54b76 100644 --- a/app/src/main/java/io/plaidapp/ui/widget/FABToggle.java +++ b/app/src/main/java/io/plaidapp/ui/widget/FABToggle.java @@ -17,6 +17,7 @@ package io.plaidapp.ui.widget; import android.content.Context; +import android.support.v7.widget.AppCompatImageButton; import android.util.AttributeSet; import android.widget.Checkable; import android.widget.ImageButton; @@ -24,7 +25,7 @@ /** * A {@link Checkable} {@link ImageButton} which can be offset vertically. */ -public class FABToggle extends ImageButton implements Checkable { +public class FABToggle extends AppCompatImageButton implements Checkable { private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked }; diff --git a/app/src/main/java/io/plaidapp/ui/widget/ForegroundImageView.java b/app/src/main/java/io/plaidapp/ui/widget/ForegroundImageView.java index 9020ab5b1..6a158f9da 100644 --- a/app/src/main/java/io/plaidapp/ui/widget/ForegroundImageView.java +++ b/app/src/main/java/io/plaidapp/ui/widget/ForegroundImageView.java @@ -21,6 +21,7 @@ import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; +import android.support.v7.widget.AppCompatImageView; import android.util.AttributeSet; import android.view.ViewOutlineProvider; import android.widget.ImageView; @@ -30,7 +31,7 @@ /** * An extension to {@link ImageView} which has a foreground drawable. */ -public class ForegroundImageView extends ImageView { +public class ForegroundImageView extends AppCompatImageView { private Drawable foreground; diff --git a/app/src/main/java/io/plaidapp/ui/widget/InkPageIndicator.java b/app/src/main/java/io/plaidapp/ui/widget/InkPageIndicator.java index 5a4515e3b..a4ddcc89e 100644 --- a/app/src/main/java/io/plaidapp/ui/widget/InkPageIndicator.java +++ b/app/src/main/java/io/plaidapp/ui/widget/InkPageIndicator.java @@ -96,9 +96,6 @@ public class InkPageIndicator extends View implements ViewPager.OnPageChangeList private final Path unselectedDotRightPath; private final RectF rectF; - // animation - private ValueAnimator moveAnimation; - private AnimatorSet joiningAnimationSet; private PendingRetreatAnimator retreatAnimation; private PendingRevealAnimator[] revealAnimations; private final Interpolator interpolator; @@ -588,7 +585,7 @@ private void setSelectedPage(int now) { // retreat animations when it has moved 75% of the way. // The retreat animation in turn will kick of reveal anims when the // retreat has passed any dots to be revealed - moveAnimation = createMoveSelectedAnimator(dotCenterX[now], previousPage, now, steps); + ValueAnimator moveAnimation = createMoveSelectedAnimator(dotCenterX[now], previousPage, now, steps); moveAnimation.start(); } @@ -664,12 +661,6 @@ private void setDotRevealFraction(int dot, float fraction) { postInvalidateOnAnimation(); } - private void cancelJoiningAnimations() { - if (joiningAnimationSet != null && joiningAnimationSet.isRunning()) { - joiningAnimationSet.cancel(); - } - } - /** * A {@link ValueAnimator} that starts once a given predicate returns true. */ @@ -766,7 +757,6 @@ public void onAnimationUpdate(ValueAnimator valueAnimator) { addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { - cancelJoiningAnimations(); clearJoiningFractions(); // we need to set this so that the dots are hidden until the reveal anim runs for (int dot : dotsToHide) { diff --git a/app/src/main/res/layout/account_dropdown_item.xml b/app/src/main/res/layout/account_dropdown_item.xml index 966471de7..46fc0df1d 100644 --- a/app/src/main/res/layout/account_dropdown_item.xml +++ b/app/src/main/res/layout/account_dropdown_item.xml @@ -23,7 +23,7 @@ android:paddingEnd="@dimen/padding_normal" android:paddingStart="@dimen/padding_normal" android:background="@drawable/mid_grey_bounded_ripple" - android:maxLines="1" + android:singleLine="true" android:ellipsize="marquee" android:textAppearance="?android:attr/textAppearanceLargePopupMenu" style="?android:attr/dropDownItemStyle" /> diff --git a/app/src/main/res/values/attrs_dynamic_text_view.xml b/app/src/main/res/values/attrs_dynamic_text_view.xml deleted file mode 100644 index 31792e971..000000000 --- a/app/src/main/res/values/attrs_dynamic_text_view.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - -