diff --git a/docs-android/app/app.iml b/docs-android/app/app.iml index 7821ca38..55cf428a 100644 --- a/docs-android/app/app.iml +++ b/docs-android/app/app.iml @@ -98,6 +98,7 @@ + diff --git a/docs-android/app/build.gradle b/docs-android/app/build.gradle index 7a40c4ba..710b9bf4 100644 --- a/docs-android/app/build.gradle +++ b/docs-android/app/build.gradle @@ -36,4 +36,5 @@ dependencies { compile 'com.loopj.android:android-async-http:1.4.6' compile 'it.sephiroth.android.library.imagezoom:imagezoom:1.0.5' compile 'de.greenrobot:eventbus:2.4.0' + compile 'com.shamanland:fab:0.0.5' } diff --git a/docs-android/app/src/main/java/com/sismics/docs/ui/view/FloatingActionButton.java b/docs-android/app/src/main/java/com/sismics/docs/ui/view/FloatingActionButton.java new file mode 100644 index 00000000..0fde5338 --- /dev/null +++ b/docs-android/app/src/main/java/com/sismics/docs/ui/view/FloatingActionButton.java @@ -0,0 +1,268 @@ +package com.sismics.docs.ui.view; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.LayerDrawable; +import android.os.Build; +import android.util.AttributeSet; +import android.widget.ImageButton; +import android.widget.ImageView; + +/** + * A circular button made of paper that lifts and emits ink reactions on press. + *

+ * This widget supports two sizes: {@link #SIZE_NORMAL} and {@link #SIZE_MINI} + * according to Promoted Actions pattern. + *

+ * Like an {@link ImageView} this widget require {@code android:src} attribute. + * According to official documentation this drawable should be not more than {@code 24dp}. + *

+ * Use theme to customize all floating buttons in your app: + *

+ * Declare own style: + *

+ * <style name="AppTheme.Fab" parent="FloatingActionButton">
+ *   <item name="floatingActionButtonColor">@color/my_fab_color</item>
+ * </style>
+ * 
+ * Link this style in your theme: + *
+ * <style name="AppTheme" parent="android:Theme">
+ *   <item name="floatingActionButtonStyle">@style/AppTheme.Fab</item>
+ * </style>
+ * 
+ *

+ * Customizing in layout.xml: + *

+ * <com.shamanland.fab.FloatingActionButton
+ *   android:layout_width="wrap_content"
+ *   android:layout_height="wrap_content"
+ *   android:src="@drawable/ic_action_my"
+ *   app:floatingActionButtonColor="@color/my_fab_color"
+ *   app:floatingActionButtonSize="mini"
+ *   />
+ * 
+ *

+ * Customizing in java-code: + *

+ * FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
+ * fab.setSize(FloatingActionButton.SIZE_MINI);
+ * fab.setColor(Color.RED);
+ * // NOTE invoke this method after setting new values!
+ * fab.initBackground();
+ * // NOTE standard method of ImageView
+ * fab.setImageResource(R.drawable.ic_action_my);
+ * 
+ */ +public class FloatingActionButton extends ImageButton { + /** + * Constant representing normal size {@code 56dp}. Value: 0x0 + */ + public static final int SIZE_NORMAL = 0; + + /** + * Constant representing mini size {@code 40dp}. Value: 0x1 + */ + public static final int SIZE_MINI = 1; + + private int mSize; + private int mColor; + private ColorStateList mColorStateList; + + private GradientDrawable mCircleDrawable; + + /** + * Gets abstract size of this button. + * + * @return {@link #SIZE_NORMAL} or {@link #SIZE_MINI} + */ + public int getSize() { + return mSize; + } + + /** + * Sets abstract size for this button. + *

+ * Xml attribute: {@code app:floatingActionButtonSize} + * + * @param size {@link #SIZE_NORMAL} or {@link #SIZE_MINI} + */ + public void setSize(int size) { + mSize = size; + } + + /** + * Gets background color of this button. + * + * @return color + */ + public int getColor() { + return mColor; + } + + /** + * Sets background color for this button. + *

+ * Xml attribute: {@code app:floatingActionButtonColor} + * + * @param color color + */ + public void setColor(int color) { + mColor = color; + } + + /** + * Gets color state list used as background for this button. + * + * @return may be null + */ + public ColorStateList getColorStateList() { + return mColorStateList; + } + + /** + * Sets color state list as background for this button. + *

+ * Xml attribute: {@code app:floatingActionButtonColor} + * + * @param colorStateList color + */ + public void setColorStateList(ColorStateList colorStateList) { + mColorStateList = colorStateList; + } + + public FloatingActionButton(Context context) { + super(context); + init(context, null, 0); + } + + public FloatingActionButton(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs, com.shamanland.fab.R.attr.floatingActionButtonStyle); + } + + public FloatingActionButton(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(context, attrs, defStyle); + } + + private void init(Context context, AttributeSet attrs, int defStyle) { + TypedArray a; + + try { + if (isInEditMode()) { + return; + } + + if (attrs == null) { + return; + } + + Resources.Theme theme = context.getTheme(); + if (theme == null) { + return; + } + + a = theme.obtainStyledAttributes(attrs, com.shamanland.fab.R.styleable.FloatingActionButton, defStyle, com.shamanland.fab.R.style.FloatingActionButton_Dark); + if (a == null) { + return; + } + } finally { + mSize = SIZE_NORMAL; + mColor = Color.GRAY; + mColorStateList = null; + } + + try { + initAttrs(a); + } finally { + a.recycle(); + } + + initBackground(); + } + + private void initAttrs(TypedArray a) { + setSize(a.getInteger(com.shamanland.fab.R.styleable.FloatingActionButton_floatingActionButtonSize, SIZE_NORMAL)); + setColor(a.getColor(com.shamanland.fab.R.styleable.FloatingActionButton_floatingActionButtonColor, Color.GRAY)); + setColorStateList(a.getColorStateList(com.shamanland.fab.R.styleable.FloatingActionButton_floatingActionButtonColor)); + } + + /** + * Inflate and initialize background drawable for this view with arguments + * inflated from xml or specified using {@link #setSize(int)} or {@link #setColor(int)} + *

+ * Invoked from constructor, but it's allowed to invoke this method manually from code. + */ + public void initBackground() { + final int backgroundId; + + if (mSize == SIZE_MINI) { + backgroundId = com.shamanland.fab.R.drawable.com_shamanland_fab_circle_mini; + } else { + backgroundId = com.shamanland.fab.R.drawable.com_shamanland_fab_circle_normal; + } + + Drawable background = getResources().getDrawable(backgroundId); + + if (background instanceof LayerDrawable) { + LayerDrawable layers = (LayerDrawable) background; + if (layers.getNumberOfLayers() == 2) { + Drawable shadow = layers.getDrawable(0); + Drawable circle = layers.getDrawable(1); + + if (shadow instanceof GradientDrawable) { + ((GradientDrawable) shadow.mutate()).setGradientRadius(getShadowRadius(shadow, circle)); + } + + if (circle instanceof GradientDrawable) { + mCircleDrawable = (GradientDrawable) circle.mutate(); + mCircleDrawable.setColor(mColor); + } + } + } + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { + //noinspection deprecation + setBackgroundDrawable(background); + } else { + setBackground(background); + } + } + + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + + if (mCircleDrawable != null && mColorStateList != null) { + mCircleDrawable.setColor(mColorStateList.getColorForState(getDrawableState(), mColor)); + + // NOTE maybe this line is required only for Gingerbread + invalidate(); + } + } + + /** + * Calculates required radius of shadow. + * + * @param shadow underlay drawable + * @param circle overlay drawable + * @return calculated radius, always >= 1 + */ + protected static int getShadowRadius(Drawable shadow, Drawable circle) { + int radius = 0; + + if (shadow != null && circle != null) { + Rect rect = new Rect(); + radius = (circle.getIntrinsicWidth() + (shadow.getPadding(rect) ? rect.left + rect.right : 0)) / 2; + } + + return Math.max(1, radius); + } +} \ No newline at end of file diff --git a/docs-android/app/src/main/res/drawable-xhdpi/ic_add_white_24dp.png b/docs-android/app/src/main/res/drawable-xhdpi/ic_add_white_24dp.png new file mode 100644 index 00000000..67042105 Binary files /dev/null and b/docs-android/app/src/main/res/drawable-xhdpi/ic_add_white_24dp.png differ diff --git a/docs-android/app/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png b/docs-android/app/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png new file mode 100644 index 00000000..72cedcad Binary files /dev/null and b/docs-android/app/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png differ diff --git a/docs-android/app/src/main/res/layout/doc_list_fragment.xml b/docs-android/app/src/main/res/layout/doc_list_fragment.xml index 23553a8f..3b9104f2 100644 --- a/docs-android/app/src/main/res/layout/doc_list_fragment.xml +++ b/docs-android/app/src/main/res/layout/doc_list_fragment.xml @@ -1,6 +1,6 @@ - @@ -37,4 +37,17 @@ android:textSize="16sp" android:layout_centerInParent="true"/> + + \ No newline at end of file