/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.litho.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.widget.ProgressBar;
import com.facebook.litho.ComponentContext;
import com.facebook.litho.ComponentLayout;
import com.facebook.litho.Output;
import com.facebook.litho.R;
import com.facebook.litho.Size;
import com.facebook.litho.SizeSpec;
import com.facebook.litho.annotations.FromPrepare;
import com.facebook.litho.annotations.MountSpec;
import com.facebook.litho.annotations.OnCreateMountContent;
import com.facebook.litho.annotations.OnLoadStyle;
import com.facebook.litho.annotations.OnMeasure;
import com.facebook.litho.annotations.OnMount;
import com.facebook.litho.annotations.OnPrepare;
import com.facebook.litho.annotations.OnUnmount;
import com.facebook.litho.annotations.Prop;
import com.facebook.litho.annotations.PropDefault;
import com.facebook.litho.annotations.ResType;
import com.facebook.litho.utils.MeasureUtils;
/**
* Renders an infinitely spinning progress bar.
*
* @prop indeterminateDrawable Drawable to be shown to show progress.
* @prop color Tint color for the drawable.
*/
@MountSpec(isPureRender = true)
class ProgressSpec {
static final int DEFAULT_SIZE = 50;
@PropDefault static final int color = Color.TRANSPARENT;
@OnLoadStyle
static void onLoadStyle(
ComponentContext c,
Output<Drawable> indeterminateDrawable) {
indeterminateDrawable.set(getStyledIndeterminateDrawable(c, 0));
}
@OnPrepare
static void onPrepare(
ComponentContext c,
@Prop(optional = true, resType = ResType.DRAWABLE) Drawable indeterminateDrawable,
Output<Drawable> resolvedIndeterminateDrawable) {
if (indeterminateDrawable != null) {
resolvedIndeterminateDrawable.set(indeterminateDrawable);
} else {
resolvedIndeterminateDrawable.set(getStyledIndeterminateDrawable(
c,
android.R.attr.progressBarStyle));
}
}
@OnMeasure
static void onMeasure(
ComponentContext c,
ComponentLayout layout,
int widthSpec,
int heightSpec,
Size size) {
if (SizeSpec.getMode(widthSpec) == SizeSpec.UNSPECIFIED &&
SizeSpec.getMode(heightSpec) == SizeSpec.UNSPECIFIED) {
size.width = DEFAULT_SIZE;
size.height = DEFAULT_SIZE;
} else {
MeasureUtils.measureWithEqualDimens(widthSpec, heightSpec, size);
}
}
@OnMount
static void onMount(
ComponentContext c,
ProgressBar progressBar,
@Prop(optional = true, resType = ResType.COLOR) int color,
@FromPrepare Drawable resolvedIndeterminateDrawable) {
if (resolvedIndeterminateDrawable != null) {
progressBar.setIndeterminateDrawable(resolvedIndeterminateDrawable);
}
if (color != Color.TRANSPARENT && progressBar.getIndeterminateDrawable() != null) {
progressBar.getIndeterminateDrawable().mutate().setColorFilter(
color,
PorterDuff.Mode.MULTIPLY);
}
}
@OnUnmount
static void onUnmount(
ComponentContext c,
ProgressBar progressBar,
@Prop(optional = true, resType = ResType.COLOR) int color,
@FromPrepare Drawable resolvedIndeterminateDrawable) {
// restore the color first, since it acts on the indeterminateDrawable
if (color != Color.TRANSPARENT && progressBar.getIndeterminateDrawable() != null) {
progressBar.getIndeterminateDrawable().mutate().clearColorFilter();
}
progressBar.setIndeterminateDrawable(null);
}
@OnCreateMountContent
static ProgressBar onCreateMountContent(ComponentContext c) {
return new ProgressView(c);
}
static Drawable getStyledIndeterminateDrawable(ComponentContext c, int defStyle) {
Drawable indeterminateDrawable = null;
final TypedArray styledAttributes = c.obtainStyledAttributes(R.styleable.Progress, defStyle);
for (int i = 0, size = styledAttributes.getIndexCount(); i < size; i++) {
final int attr = styledAttributes.getIndex(i);
if (attr == R.styleable.Progress_android_indeterminateDrawable) {
indeterminateDrawable =
c.getResources().getDrawable(styledAttributes.getResourceId(attr, 0));
}
}
styledAttributes.recycle();
return indeterminateDrawable;
}
private static class ProgressView extends ProgressBar {
private ProgressView(Context context) {
super(context);
}
/**
* ProgressBar is not setting the right bounds on the drawable passed to
* {@link ProgressBar#setIndeterminateDrawable(Drawable)}. Overriding the method and setting
* the bounds before passing the drawable in solves the issue.
*/
@Override
public void setIndeterminateDrawable(Drawable d) {
if (d != null) {
d.setBounds(0, 0, getWidth(), getHeight());
}
super.setIndeterminateDrawable(d);
}
}
}