From 55163b7a60f810b102651f638a2e92753bf475d8 Mon Sep 17 00:00:00 2001 From: Victor Shcherb Date: Sat, 14 Mar 2015 20:37:51 +0100 Subject: [PATCH] Add lib for eclipse compile --- .../DistanceCalculatorPlugin.java | 8 +- .../parkingpoint/ParkingPositionPlugin.java | 10 +- eclipse-compile/fab/.classpath | 9 + eclipse-compile/fab/.gitignore | 2 + eclipse-compile/fab/.project | 39 + eclipse-compile/fab/AndroidManifest.xml | 21 + .../com/software/shell/fab/ActionButton.java | 1432 +++++++++++++++++ .../fab/ActionButtonOutlineProvider.java | 74 + .../shell/fab/FloatingActionButton.java | 198 +++ .../software/shell/fab/MetricsConverter.java | 50 + eclipse-compile/fab/project.properties | 15 + .../fab/res/anim-v11/fab_jump_from_down.xml | 37 + .../fab/res/anim-v11/fab_jump_from_right.xml | 38 + .../fab/res/anim-v11/fab_jump_to_down.xml | 38 + .../fab/res/anim-v11/fab_jump_to_right.xml | 38 + .../fab/res/anim-v11/fab_roll_from_down.xml | 35 + .../fab/res/anim-v11/fab_roll_from_right.xml | 35 + .../fab/res/anim-v11/fab_roll_to_down.xml | 36 + .../fab/res/anim-v11/fab_roll_to_right.xml | 36 + .../fab/res/anim-v11/fab_scale_down.xml | 30 + .../fab/res/anim-v11/fab_scale_up.xml | 29 + eclipse-compile/fab/res/anim/fab_fade_in.xml | 25 + eclipse-compile/fab/res/anim/fab_fade_out.xml | 25 + .../fab/res/anim/fab_jump_from_down.xml | 36 + .../fab/res/anim/fab_jump_from_right.xml | 37 + .../fab/res/anim/fab_jump_to_down.xml | 37 + .../fab/res/anim/fab_jump_to_right.xml | 37 + .../fab/res/anim/fab_roll_from_down.xml | 48 + .../fab/res/anim/fab_roll_from_right.xml | 48 + .../fab/res/anim/fab_roll_to_down.xml | 48 + .../fab/res/anim/fab_roll_to_right.xml | 48 + .../fab/res/anim/fab_scale_down.xml | 41 + eclipse-compile/fab/res/anim/fab_scale_up.xml | 42 + .../fab/res/drawable-hdpi/fab_plus_icon.png | Bin 0 -> 1104 bytes .../fab/res/drawable-mdpi/fab_plus_icon.png | Bin 0 -> 1055 bytes .../fab/res/drawable-xhdpi/fab_plus_icon.png | Bin 0 -> 1113 bytes .../fab/res/drawable-xxhdpi/fab_plus_icon.png | Bin 0 -> 1182 bytes .../res/drawable-xxxhdpi/fab_plus_icon.png | Bin 0 -> 1105 bytes .../fab/res/values-sw600dp/dimens.xml | 23 + eclipse-compile/fab/res/values/attrs.xml | 47 + eclipse-compile/fab/res/values/colors.xml | 86 + eclipse-compile/fab/res/values/dimens.xml | 24 + 42 files changed, 2851 insertions(+), 11 deletions(-) create mode 100644 eclipse-compile/fab/.classpath create mode 100644 eclipse-compile/fab/.gitignore create mode 100644 eclipse-compile/fab/.project create mode 100644 eclipse-compile/fab/AndroidManifest.xml create mode 100644 eclipse-compile/fab/java/com/software/shell/fab/ActionButton.java create mode 100644 eclipse-compile/fab/java/com/software/shell/fab/ActionButtonOutlineProvider.java create mode 100644 eclipse-compile/fab/java/com/software/shell/fab/FloatingActionButton.java create mode 100644 eclipse-compile/fab/java/com/software/shell/fab/MetricsConverter.java create mode 100644 eclipse-compile/fab/project.properties create mode 100644 eclipse-compile/fab/res/anim-v11/fab_jump_from_down.xml create mode 100644 eclipse-compile/fab/res/anim-v11/fab_jump_from_right.xml create mode 100644 eclipse-compile/fab/res/anim-v11/fab_jump_to_down.xml create mode 100644 eclipse-compile/fab/res/anim-v11/fab_jump_to_right.xml create mode 100644 eclipse-compile/fab/res/anim-v11/fab_roll_from_down.xml create mode 100644 eclipse-compile/fab/res/anim-v11/fab_roll_from_right.xml create mode 100644 eclipse-compile/fab/res/anim-v11/fab_roll_to_down.xml create mode 100644 eclipse-compile/fab/res/anim-v11/fab_roll_to_right.xml create mode 100644 eclipse-compile/fab/res/anim-v11/fab_scale_down.xml create mode 100644 eclipse-compile/fab/res/anim-v11/fab_scale_up.xml create mode 100644 eclipse-compile/fab/res/anim/fab_fade_in.xml create mode 100644 eclipse-compile/fab/res/anim/fab_fade_out.xml create mode 100644 eclipse-compile/fab/res/anim/fab_jump_from_down.xml create mode 100644 eclipse-compile/fab/res/anim/fab_jump_from_right.xml create mode 100644 eclipse-compile/fab/res/anim/fab_jump_to_down.xml create mode 100644 eclipse-compile/fab/res/anim/fab_jump_to_right.xml create mode 100644 eclipse-compile/fab/res/anim/fab_roll_from_down.xml create mode 100644 eclipse-compile/fab/res/anim/fab_roll_from_right.xml create mode 100644 eclipse-compile/fab/res/anim/fab_roll_to_down.xml create mode 100644 eclipse-compile/fab/res/anim/fab_roll_to_right.xml create mode 100644 eclipse-compile/fab/res/anim/fab_scale_down.xml create mode 100644 eclipse-compile/fab/res/anim/fab_scale_up.xml create mode 100644 eclipse-compile/fab/res/drawable-hdpi/fab_plus_icon.png create mode 100644 eclipse-compile/fab/res/drawable-mdpi/fab_plus_icon.png create mode 100644 eclipse-compile/fab/res/drawable-xhdpi/fab_plus_icon.png create mode 100644 eclipse-compile/fab/res/drawable-xxhdpi/fab_plus_icon.png create mode 100644 eclipse-compile/fab/res/drawable-xxxhdpi/fab_plus_icon.png create mode 100644 eclipse-compile/fab/res/values-sw600dp/dimens.xml create mode 100644 eclipse-compile/fab/res/values/attrs.xml create mode 100644 eclipse-compile/fab/res/values/colors.xml create mode 100644 eclipse-compile/fab/res/values/dimens.xml diff --git a/OsmAnd/src/net/osmand/plus/distancecalculator/DistanceCalculatorPlugin.java b/OsmAnd/src/net/osmand/plus/distancecalculator/DistanceCalculatorPlugin.java index 25ade182d4..3de17feeec 100644 --- a/OsmAnd/src/net/osmand/plus/distancecalculator/DistanceCalculatorPlugin.java +++ b/OsmAnd/src/net/osmand/plus/distancecalculator/DistanceCalculatorPlugin.java @@ -31,7 +31,6 @@ import net.osmand.plus.OsmandPlugin; import net.osmand.plus.OsmandSettings.CommonPreference; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; -import net.osmand.plus.activities.SettingsActivity; import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.plus.views.ContextMenuLayer; import net.osmand.plus.views.MapInfoLayer; @@ -56,7 +55,6 @@ import android.graphics.Paint.Style; import android.graphics.Path; import android.graphics.PointF; import android.os.AsyncTask; -import android.preference.PreferenceScreen; import android.text.Editable; import android.text.TextWatcher; import android.view.View; @@ -118,7 +116,7 @@ public class DistanceCalculatorPlugin extends OsmandPlugin { private void registerWidget(MapActivity activity) { MapInfoLayer mapInfoLayer = activity.getMapLayers().getMapInfoLayer(); if (mapInfoLayer != null ) { - distanceControl = createDistanceControl(activity, mapInfoLayer.getPaintText(), mapInfoLayer.getPaintSubText()); + distanceControl = createDistanceControl(activity); mapInfoLayer.getMapInfoControls().registerSideWidget(distanceControl, R.drawable.widget_distance, R.drawable.widget_distance, R.string.map_widget_distancemeasurement, "distance.measurement", false, 21); mapInfoLayer.recreateControls(); @@ -371,8 +369,8 @@ public class DistanceCalculatorPlugin extends OsmandPlugin { } - private TextInfoWidget createDistanceControl(final MapActivity activity, Paint paintText, Paint paintSubText) { - final TextInfoWidget distanceControl = new TextInfoWidget(activity, 0, paintText, paintSubText); + private TextInfoWidget createDistanceControl(final MapActivity activity) { + final TextInfoWidget distanceControl = new TextInfoWidget(activity); distanceControl.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/OsmAnd/src/net/osmand/plus/parkingpoint/ParkingPositionPlugin.java b/OsmAnd/src/net/osmand/plus/parkingpoint/ParkingPositionPlugin.java index 45756c8f2b..bdc556a6e1 100644 --- a/OsmAnd/src/net/osmand/plus/parkingpoint/ParkingPositionPlugin.java +++ b/OsmAnd/src/net/osmand/plus/parkingpoint/ParkingPositionPlugin.java @@ -18,7 +18,6 @@ import net.osmand.plus.views.AnimateDraggingMapThread; import net.osmand.plus.views.MapInfoLayer; import net.osmand.plus.views.OsmandMapLayer.DrawSettings; import net.osmand.plus.views.OsmandMapTileView; -import net.osmand.plus.views.mapwidgets.BaseMapWidget; import net.osmand.plus.views.mapwidgets.TextInfoWidget; import android.app.Activity; import android.app.AlertDialog; @@ -26,7 +25,6 @@ import android.app.AlertDialog.Builder; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; -import android.graphics.Paint; import android.text.format.DateFormat; import android.text.format.Time; import android.view.View; @@ -56,7 +54,7 @@ public class ParkingPositionPlugin extends OsmandPlugin { private OsmandApplication app; private ParkingPositionLayer parkingLayer; - private BaseMapWidget parkingPlaceControl; + private TextInfoWidget parkingPlaceControl; private final CommonPreference parkingLat; private final CommonPreference parkingLon; private CommonPreference parkingType; @@ -191,7 +189,7 @@ public class ParkingPositionPlugin extends OsmandPlugin { private void registerWidget(MapActivity activity) { MapInfoLayer mapInfoLayer = activity.getMapLayers().getMapInfoLayer(); if (mapInfoLayer != null) { - parkingPlaceControl = createParkingPlaceInfoControl(activity, mapInfoLayer.getPaintText(), mapInfoLayer.getPaintSubText()); + parkingPlaceControl = createParkingPlaceInfoControl(activity); mapInfoLayer.getMapInfoControls().registerSideWidget(parkingPlaceControl, R.drawable.widget_parking, R.drawable.widget_parking, R.string.map_widget_parking, "parking", false, 8); mapInfoLayer.recreateControls(); @@ -443,8 +441,8 @@ public class ParkingPositionPlugin extends OsmandPlugin { * the current position on the map * and the location of the parked car */ - private TextInfoWidget createParkingPlaceInfoControl(final MapActivity map, Paint paintText, Paint paintSubText) { - TextInfoWidget parkingPlaceControl = new TextInfoWidget(map, 0, paintText, paintSubText) { + private TextInfoWidget createParkingPlaceInfoControl(final MapActivity map) { + TextInfoWidget parkingPlaceControl = new TextInfoWidget(map) { private float[] calculations = new float[1]; private int cachedMeters = 0; diff --git a/eclipse-compile/fab/.classpath b/eclipse-compile/fab/.classpath new file mode 100644 index 0000000000..c6e9dc9f1d --- /dev/null +++ b/eclipse-compile/fab/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/eclipse-compile/fab/.gitignore b/eclipse-compile/fab/.gitignore new file mode 100644 index 0000000000..e614fbbef9 --- /dev/null +++ b/eclipse-compile/fab/.gitignore @@ -0,0 +1,2 @@ +bin +gen diff --git a/eclipse-compile/fab/.project b/eclipse-compile/fab/.project new file mode 100644 index 0000000000..b53f0578e5 --- /dev/null +++ b/eclipse-compile/fab/.project @@ -0,0 +1,39 @@ + + + ShellFab + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + org.eclipse.xtext.ui.shared.xtextNature + + diff --git a/eclipse-compile/fab/AndroidManifest.xml b/eclipse-compile/fab/AndroidManifest.xml new file mode 100644 index 0000000000..7e0d38def5 --- /dev/null +++ b/eclipse-compile/fab/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + diff --git a/eclipse-compile/fab/java/com/software/shell/fab/ActionButton.java b/eclipse-compile/fab/java/com/software/shell/fab/ActionButton.java new file mode 100644 index 0000000000..0da0da5d0c --- /dev/null +++ b/eclipse-compile/fab/java/com/software/shell/fab/ActionButton.java @@ -0,0 +1,1432 @@ +/* + * Copyright 2015 Shell Software 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. + * + * File created: 2015-01-17 10:39:13 + */ + +package com.software.shell.fab; + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.*; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewOutlineProvider; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; + +/** + * This class represents a Action Button, which is used in + * Material Design + * + * @author Vladislav + * @version 1.0.3 + * @since 1.0.0 + */ +public class ActionButton extends View { + + /** + * Logging tag + */ + private static final String LOG_TAG = "FAB"; + + /** + * Action Button type + */ + private Type type = Type.DEFAULT; + + /** + * Action Button state + */ + private State state = State.NORMAL; + + /** + * Action Button color in {@link State#NORMAL} state + */ + private int buttonColor = Color.LTGRAY; + + /** + * Action Button color in {@link State#PRESSED} state + */ + private int buttonColorPressed = Color.DKGRAY; + + /** + * Shadow radius expressed in actual pixels + */ + private float shadowRadius = MetricsConverter.dpToPx(getContext(), 2.0f); + + /** + * Shadow X-axis offset expressed in actual pixels + */ + private float shadowXOffset = MetricsConverter.dpToPx(getContext(), 1.0f); + + /** + * Shadow Y-axis offset expressed in actual pixels + */ + private float shadowYOffset = MetricsConverter.dpToPx(getContext(), 1.5f); + + /** + * Shadow color + */ + private int shadowColor = Color.parseColor("#757575"); + + /** + * Stroke width + */ + private float strokeWidth = 0.0f; + + /** + * Stroke color + */ + private int strokeColor = Color.BLACK; + + /** + * Action Button image drawable centered inside the view + */ + private Drawable image; + + /** + * Size of the Action Button image inside the view + */ + private float imageSize = MetricsConverter.dpToPx(getContext(), 24.0f); + + /** + * Animation, which is used while showing Action Button + */ + private Animation showAnimation; + + /** + * Animation, which is used while hiding or dismissing Action Button + */ + private Animation hideAnimation; + + /** + * {@link android.graphics.Paint}, which is used for drawing the elements of + * Action Button + */ + protected final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + + /** + * Creates an instance of the Action Button + *

+ * Used when instantiating Action Button programmatically + * + * @param context context the view is running in + */ + public ActionButton(Context context) { + super(context); + initActionButton(); + } + + /** + * Creates an instance of the Action Button + *

+ * Used when inflating the declared Action Button + * within XML resource + * + * @param context context the view is running in + * @param attrs attributes of the XML tag that is inflating the view + */ + public ActionButton(Context context, AttributeSet attrs) { + super(context, attrs); + initActionButton(context, attrs, 0, 0); + } + + /** + * Creates an instance of the Action Button + *

+ * Used when inflating the declared Action Button + * within XML resource + * + * @param context context the view is running in + * @param attrs attributes of the XML tag that is inflating the view + * @param defStyleAttr attribute in the current theme that contains a + * reference to a style resource that supplies default values for + * the view. Can be 0 to not look for defaults + */ + public ActionButton(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initActionButton(context, attrs, defStyleAttr, 0); + } + + /** + * Creates an instance of the Action Button + *

+ * Used when inflating the declared Action Button + * within XML resource + *

+ * Might be called if target API is LOLLIPOP (21) and higher + * + * @param context context the view is running in + * @param attrs attributes of the XML tag that is inflating the view + * @param defStyleAttr attribute in the current theme that contains a + * reference to a style resource that supplies default values for + * the view. Can be 0 to not look for defaults + * @param defStyleRes resource identifier of a style resource that + * supplies default values for the view, used only if + * defStyleAttr is 0 or can not be found in the theme. Can be 0 + * to not look for defaults + */ + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public ActionButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + initActionButton(context, attrs, defStyleAttr, defStyleRes); + } + + /** + * Initializes the Action Button, which is created programmatically + */ + private void initActionButton() { + initLayerType(); + Log.v(LOG_TAG, "Action Button initialized"); + } + + /** + * Initializes the Action Button, which is declared within XML resource + *

+ * Makes calls to different initialization methods for parameters initialization. + * For those parameters, which are not declared in the XML resource, + * the default value will be used + * + * @param context context the view is running in + * @param attrs attributes of the XML tag that is inflating the view + * @param defStyleAttr attribute in the current theme that contains a + * reference to a style resource that supplies default values for + * the view. Can be 0 to not look for defaults + * @param defStyleRes resource identifier of a style resource that + * supplies default values for the view, used only if + * defStyleAttr is 0 or can not be found in the theme. Can be 0 + * to not look for defaults + */ + private void initActionButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + initLayerType(); + TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ActionButton, + defStyleAttr, defStyleRes); + try { + initType(attributes); + initButtonColor(attributes); + initButtonColorPressed(attributes); + initShadowRadius(attributes); + initShadowXOffset(attributes); + initShadowYOffset(attributes); + initShadowColor(attributes); + initStrokeWidth(attributes); + initStrokeColor(attributes); + initImage(attributes); + initImageSize(attributes); + initShowAnimation(attributes); + initHideAnimation(attributes); + } catch (Exception e) { + Log.e(LOG_TAG, "Unable to read attr", e); + } finally { + attributes.recycle(); + } + Log.v(LOG_TAG, "Action Button initialized"); + } + + /** + * Initializes the layer type needed for shadows drawing + *

+ * Might be called if target API is HONEYCOMB (11) and higher + */ + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + private void initLayerType() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + setLayerType(LAYER_TYPE_SOFTWARE, paint); + Log.v(LOG_TAG, "Layer type initialized"); + } + } + + /** + * Initializes the {@link Type} of Action Button + * + * @param attrs attributes of the XML tag that is inflating the view + */ + private void initType(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_type)) { + final int id = attrs.getInteger(R.styleable.ActionButton_type, type.getId()); + type = Type.forId(id); + Log.v(LOG_TAG, "Initialized type: " + getType()); + } + } + + /** + * Initializes the Action Button color for + * {@link #state} set to {@link State#NORMAL} + * + * @param attrs attributes of the XML tag that is inflating the view + */ + private void initButtonColor(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_button_color)) { + buttonColor = attrs.getColor(R.styleable.ActionButton_button_color, buttonColor); + Log.v(LOG_TAG, "Initialized button color: " + getButtonColor()); + } + } + + /** + * Initializes the Action Button color for + * {@link #state} set to {@link State#PRESSED} + * + * @param attrs attributes of the XML tag that is inflating the view + */ + private void initButtonColorPressed(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_button_colorPressed)) { + buttonColorPressed = attrs.getColor(R.styleable.ActionButton_button_colorPressed, + buttonColorPressed); + Log.v(LOG_TAG, "Initialized button color pressed: " + getButtonColorPressed()); + } + } + + /** + * Initializes the shadow radius + * + * @param attrs attributes of the XML tag that is inflating the view + */ + private void initShadowRadius(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_shadow_radius)) { + shadowRadius = attrs.getDimension(R.styleable.ActionButton_shadow_radius, shadowRadius); + Log.v(LOG_TAG, "Initialized shadow radius: " + getShadowRadius()); + } + } + + /** + * Initializes the shadow X-axis offset + * + * @param attrs attributes of the XML tag that is inflating the view + */ + private void initShadowXOffset(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_shadow_xOffset)) { + shadowXOffset = attrs.getDimension(R.styleable.ActionButton_shadow_xOffset, shadowXOffset); + Log.v(LOG_TAG, "Initialized shadow X-axis offset: " + getShadowXOffset()); + } + } + + /** + * Initializes the shadow Y-axis offset + * + * @param attrs attributes of the XML tag that is inflating the view + */ + private void initShadowYOffset(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_shadow_yOffset)) { + shadowYOffset = attrs.getDimension(R.styleable.ActionButton_shadow_yOffset, shadowYOffset); + Log.v(LOG_TAG, "Initialized shadow Y-axis offset: " + getShadowYOffset()); + } + } + + /** + * Initializes the shadow color + * + * @param attrs attributes of the XML tag that is inflating the view + */ + private void initShadowColor(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_shadow_color)) { + shadowColor = attrs.getColor(R.styleable.ActionButton_shadow_color, shadowColor); + Log.v(LOG_TAG, "Initialized shadow color: " + getShadowColor()); + } + } + + /** + * Initializes the stroke width + * + * @param attrs attributes of the XML tag that is inflating the view + */ + private void initStrokeWidth(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_stroke_width)) { + strokeWidth = attrs.getDimension(R.styleable.ActionButton_stroke_width, strokeWidth); + Log.v(LOG_TAG, "Initialized stroke width: " + getStrokeWidth()); + } + } + + /** + * Initializes the stroke color + * + * @param attrs attributes of the XML tag that is inflating the view + */ + private void initStrokeColor(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_stroke_color)) { + strokeColor = attrs.getColor(R.styleable.ActionButton_stroke_color, strokeColor); + Log.v(LOG_TAG, "Initialized stroke color: " + getStrokeColor()); + } + } + + /** + * Initializes the animation, which is used while showing + * Action Button + * + * @param attrs attributes of the XML tag that is inflating the view + */ + private void initShowAnimation(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_show_animation)) { + final int animResId = attrs.getResourceId(R.styleable.ActionButton_show_animation, + Animations.NONE.animResId); + showAnimation = Animations.load(getContext(), animResId); + Log.v(LOG_TAG, "Initialized animation on show"); + } + } + + /** + * Initializes the animation, which is used while hiding or dismissing + * Action Button + * + * @param attrs attributes of the XML tag that is inflating the view + */ + private void initHideAnimation(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_hide_animation)) { + final int animResId = attrs.getResourceId(R.styleable.ActionButton_hide_animation, + Animations.NONE.animResId); + hideAnimation = Animations.load(getContext(), animResId); + Log.v(LOG_TAG, "Initialized animation on hide"); + } + } + + /** + * Initializes the image inside Action Button + * + * @param attrs attributes of the XML tag that is inflating the view + */ + private void initImage(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_image)) { + image = attrs.getDrawable(R.styleable.ActionButton_image); + Log.v(LOG_TAG, "Initialized image"); + } + } + + /** + * Initializes the image size inside Action Button + *

+ * Changing the default size of the image breaks the rules of + * Material Design + * + * @param attrs attributes of the XML tag that is inflating the view + */ + private void initImageSize(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_image_size)) { + imageSize = attrs.getDimension(R.styleable.ActionButton_image_size, imageSize); + Log.v(LOG_TAG, "Initialized image size: " + getImageSize()); + } + } + + /** + * Plays the {@link #showAnimation} if set + */ + public void playShowAnimation() { + startAnimation(getShowAnimation()); + } + + /** + * Plays the {@link #hideAnimation} if set + */ + public void playHideAnimation() { + startAnimation(getHideAnimation()); + } + + /** + * Makes the Action Button to appear and + * sets its visibility to {@link #VISIBLE} + *

+ * {@link #showAnimation} is played if set + */ + public void show() { + if (isHidden()) { + playShowAnimation(); + setVisibility(VISIBLE); + Log.v(LOG_TAG, "Action Button shown"); + } + } + + /** + * Makes the Action Button to disappear and + * sets its visibility to {@link #INVISIBLE} + *

+ * {@link #hideAnimation} is played if set + */ + public void hide() { + if (!isHidden() && !isDismissed()) { + playHideAnimation(); + setVisibility(INVISIBLE); + Log.v(LOG_TAG, "Action Button hidden"); + } + } + + /** + * Completely dismisses the Action Button, + * sets its visibility to {@link #GONE} and removes it from the parent view + *

+ * After calling this method any calls to {@link #show()} won't result in showing + * the Action Button so far as it is removed from the parent View + *

+ * {@link #hideAnimation} is played if set + */ + public void dismiss() { + if (!isDismissed()) { + if (!isHidden()) { + playHideAnimation(); + } + setVisibility(GONE); + ViewGroup parent = (ViewGroup) getParent(); + parent.removeView(this); + Log.v(LOG_TAG, "Action Button dismissed"); + } + } + + /** + * Checks whether Action Button is hidden + * + * @return true if Action Button is hidden, otherwise false + */ + public boolean isHidden() { + return getVisibility() == INVISIBLE; + } + + /** + * Checks whether Action Button is dismissed + * + * @return true if Action Button is dismissed, otherwise false + */ + public boolean isDismissed() { + ViewGroup parent = (ViewGroup) getParent(); + return parent == null; + } + + /** + * Returns the size of the Action Button in actual pixels (px). + * Size of the Action Button is the diameter of the main circle + * + * @return size of the Action Button in actual pixels (px) + */ + public int getButtonSize() { + final int buttonSize = (int) type.getSize(getContext()); + Log.v(LOG_TAG, "Button size is: " + buttonSize); + return buttonSize; + } + + /** + * Returns the type of the Action Button + * + * @return type of the Action Button + */ + public Type getType() { + return type; + } + + /** + * Sets the type of the Action Button and + * invalidates the layout of the view + * + * @param type type of the Action Button + */ + public void setType(Type type) { + this.type = type; + requestLayout(); + Log.v(LOG_TAG, "Type changed to: " + getType()); + } + + /** + * Returns the current state of the Action Button + * + * @return current state of the Action Button + */ + public State getState() { + return state; + } + + /** + * Sets the current state of the Action Button and + * invalidates the view + * + * @param state new state of the Action Button + */ + public void setState(State state) { + this.state = state; + invalidate(); + Log.v(LOG_TAG, "State changed to: " + getState()); + } + + /** + * Returns the Action Button color when in + * {@link State#NORMAL} state + * + * @return Action Button color when in + * {@link State#NORMAL} state + */ + public int getButtonColor() { + return buttonColor; + } + + /** + * Sets the Action Button color when in + * {@link State#NORMAL} state and invalidates the view + * + * @param buttonColor Action Button color + * when in {@link State#NORMAL} state + */ + public void setButtonColor(int buttonColor) { + this.buttonColor = buttonColor; + invalidate(); + Log.v(LOG_TAG, "Color changed to: " + getButtonColor()); + } + + /** + * Sets the Action Button color when in + * {@link State#PRESSED} state + * + * @return Action Button color when in + * {@link State#PRESSED} state + */ + public int getButtonColorPressed() { + return buttonColorPressed; + } + + /** + * Sets the Action Button color when in + * {@link State#PRESSED} state and invalidates the view + * + * @param buttonColorPressed Action Button color + * when in {@link State#PRESSED} state + */ + public void setButtonColorPressed(int buttonColorPressed) { + this.buttonColorPressed = buttonColorPressed; + invalidate(); + Log.v(LOG_TAG, "Pressed color changed to: " + getButtonColorPressed()); + } + + /** + * Checks whether Action Button has shadow by determining shadow radius + *

+ * Shadow is disabled if elevation is set API level is {@code 21 Lollipop} and higher + * + * @return true if Action Button has radius, otherwise false + */ + public boolean hasShadow() { + return !hasElevation() && getShadowRadius() > 0.0f; + } + + /** + * Returns the Action Button shadow radius in actual + * pixels (px) + * + * @return Action Button shadow radius in actual pixels (px) + */ + public float getShadowRadius() { + return shadowRadius; + } + + /** + * Sets the Action Button shadow radius and + * invalidates the layout of the view + *

+ * Must be specified in density-independent (dp) pixels, which are + * then converted into actual pixels (px). If shadow radius is set to 0, + * shadow is removed + * + * @param shadowRadius shadow radius specified in density-independent + * (dp) pixels + */ + public void setShadowRadius(float shadowRadius) { + this.shadowRadius = MetricsConverter.dpToPx(getContext(), shadowRadius); + requestLayout(); + Log.v(LOG_TAG, "Shadow radius changed to:" + getShadowRadius()); + } + + /** + * Removes the Action Button shadow by setting its radius to 0 + */ + public void removeShadow() { + if (hasShadow()) { + setShadowRadius(0.0f); + } + } + + /** + * Returns the Action Button shadow X-axis offset + * in actual pixels (px) + *

+ * If X-axis offset is greater than 0 shadow is shifted right. + * If X-axis offset is lesser than 0 shadow is shifted left. + * 0 X-axis offset means that shadow is not X-axis shifted at all + * + * @return Action Button shadow X-axis offset + * in actual pixels (px) + */ + public float getShadowXOffset() { + return shadowXOffset; + } + + /** + * Sets the Action Button shadow X-axis offset and + * invalidates the layout of the view + *

+ * If X-axis offset is greater than 0 shadow is shifted right. + * If X-axis offset is lesser than 0 shadow is shifted left. + * 0 X-axis offset means that shadow is not shifted at all + *

+ * Must be specified in density-independent (dp) pixels, which are + * then converted into actual pixels (px) + * + * @param shadowXOffset shadow X-axis offset specified in density-independent + * (dp) pixels + */ + public void setShadowXOffset(float shadowXOffset) { + this.shadowXOffset = MetricsConverter.dpToPx(getContext(), shadowXOffset); + requestLayout(); + Log.v(LOG_TAG, "Shadow X offset changed to: " + getShadowXOffset()); + } + + /** + * Returns the Action Button shadow Y-axis offset + * in actual pixels (px) + *

+ * If Y-axis offset is greater than 0 shadow is shifted down. + * If Y-axis offset is lesser than 0 shadow is shifted up. + * 0 Y-axis offset means that shadow is not Y-axis shifted at all + * + * @return Action Button shadow Y-axis offset + * in actual pixels (px) + */ + public float getShadowYOffset() { + return shadowYOffset; + } + + /** + * Sets the Action Button shadow Y-axis offset and + * invalidates the layout of the view + *

+ * If Y-axis offset is greater than 0 shadow is shifted down. + * If Y-axis offset is lesser than 0 shadow is shifted up. + * 0 Y-axis offset means that shadow is not Y-axis shifted at all + *

+ * Must be specified in density-independent (dp) pixels, which are + * then converted into actual pixels (px) + * + * @param shadowYOffset shadow Y-axis offset specified in density-independent + * (dp) pixels + */ + public void setShadowYOffset(float shadowYOffset) { + this.shadowYOffset = MetricsConverter.dpToPx(getContext(), shadowYOffset); + requestLayout(); + Log.v(LOG_TAG, "Shadow Y offset changed to:" + getShadowYOffset()); + } + + /** + * Returns Action Button shadow color + * + * @return Action Button shadow color + */ + public int getShadowColor() { + return shadowColor; + } + + /** + * Sets the Action Button shadow color and + * invalidates the view + * + * @param shadowColor Action Button color + */ + public void setShadowColor(int shadowColor) { + this.shadowColor = shadowColor; + invalidate(); + Log.v(LOG_TAG, "Shadow color changed to: " + getShadowColor()); + } + + /** + * Returns the Action Button stroke width in actual + * pixels (px) + * + * @return Action Button stroke width in actual + * pixels (px) + */ + public float getStrokeWidth() { + return strokeWidth; + } + + /** + * Checks whether Action Button has stroke by checking + * stroke width + * + * @return true if Action Button has stroke, otherwise false + */ + public boolean hasStroke() { + return getStrokeWidth() > 0.0f; + } + + /** + * Sets the Action Button stroke width and + * invalidates the layout of the view + *

+ * Stroke width value must be greater than 0. If stroke width is + * set to 0 stroke is removed + *

+ * Must be specified in density-independent (dp) pixels, which are + * then converted into actual pixels (px) + * + * @param strokeWidth stroke width specified in density-independent + * (dp) pixels + */ + public void setStrokeWidth(float strokeWidth) { + this.strokeWidth = MetricsConverter.dpToPx(getContext(), strokeWidth); + requestLayout(); + Log.v(LOG_TAG, "Stroke width changed to: " + getStrokeWidth()); + } + + /** + * Removes the Action Button stroke by setting its width to 0 + */ + public void removeStroke() { + if (hasStroke()) { + setStrokeWidth(0.0f); + } + } + + /** + * Returns the Action Button stroke color + * + * @return Action Button stroke color + */ + public int getStrokeColor() { + return strokeColor; + } + + /** + * Sets the Action Button stroke color and + * invalidates the view + * + * @param strokeColor Action Button stroke color + */ + public void setStrokeColor(int strokeColor) { + this.strokeColor = strokeColor; + invalidate(); + Log.v(LOG_TAG, "Stroke color changed to: " + getStrokeColor()); + } + + /** + * Returns the Action Button image drawable centered + * inside the view + * + * @return Action Button image drawable centered + * inside the view + */ + public Drawable getImage() { + return image; + } + + /** + * Checks whether Action Button has an image centered + * inside the view + * + * @return true if Action Button has an image centered + * inside the view, otherwise false + */ + public boolean hasImage() { + return getImage() != null; + } + + /** + * Places the image drawable centered inside the view and + * invalidates the view + *

+ * Size of the image while drawing is fit to {@link #imageSize} + * + * @param image image drawable, which will be placed centered + * inside the view + */ + public void setImageDrawable(Drawable image) { + this.image = image; + invalidate(); + Log.v(LOG_TAG, "Image drawable set"); + } + + /** + * Resolves the drawable resource id and places the resolved image drawable + * centered inside the view + * + * @param resId drawable resource id, which is to be resolved to + * image drawable and used as parameter when calling + * {@link #setImageDrawable(android.graphics.drawable.Drawable)} + */ + public void setImageResource(int resId) { + setImageDrawable(getResources().getDrawable(resId)); + } + + /** + * Creates the {@link android.graphics.drawable.BitmapDrawable} from the given + * {@link android.graphics.Bitmap} and places it centered inside the view + * + * @param bitmap bitmap, from which {@link android.graphics.drawable.BitmapDrawable} + * is created and used as parameter when calling + * {@link #setImageDrawable(android.graphics.drawable.Drawable)} + */ + public void setImageBitmap(Bitmap bitmap) { + setImageDrawable(new BitmapDrawable(getResources(), bitmap)); + } + + /** + * Removes the Action Button image by setting its value to null + */ + public void removeImage() { + if (hasImage()) { + setImageDrawable(null); + } + } + + /** + * Returns the Action Button image size in actual pixels (px). + * If Action Button image is not set returns 0 + * + * @return Action Button image size in actual pixels (px), + * 0 if image is not set + */ + public float getImageSize() { + return getImage() != null ? imageSize : 0.0f; + } + + /** + * Sets the size of the Action Button image + *

+ * Changing the default size of the image breaks the rules of + * Material Design + *

+ * Must be specified in density-independent (dp) pixels, which are + * then converted into actual pixels (px) + * + * @param size size of the Action Button image + * specified in density-independent (dp) pixels + */ + public void setImageSize(float size) { + this.imageSize = MetricsConverter.dpToPx(getContext(), size); + Log.v(LOG_TAG, "Image size changed to: " + getImageSize()); + } + + /** + * Returns an animation, which is used while showing Action Button + * + * @return animation, which is used while showing Action Button + */ + public Animation getShowAnimation() { + return showAnimation; + } + + /** + * Sets the animation, which is used while showing Action Button + * + * @param animation animation, which is to be used while showing + * Action Button + */ + public void setShowAnimation(Animation animation) { + this.showAnimation = animation; + Log.v(LOG_TAG, "Show animation set"); + } + + /** + * Sets one of the {@link Animations} as animation, which is used while showing + * Action Button + * + * @param animation one of the {@link Animations}, which is to be used while + * showing Action Button + */ + public void setShowAnimation(Animations animation) { + setShowAnimation(Animations.load(getContext(), animation.animResId)); + } + + /** + * Removes the animation, which is used while showing Action Button + */ + public void removeShowAnimation() { + setShowAnimation(Animations.NONE); + Log.v(LOG_TAG, "Show animation removed"); + } + + /** + * Returns an animation, which is used while hiding Action Button + * + * @return animation, which is used while hiding Action Button + */ + public Animation getHideAnimation() { + return hideAnimation; + } + + /** + * Sets the animation, which is used while hiding Action Button + * + * @param animation animation, which is to be used while hiding + * Action Button + */ + public void setHideAnimation(Animation animation) { + this.hideAnimation = animation; + Log.v(LOG_TAG, "Hide animation set"); + } + + /** + * Sets one of the {@link Animations} as animation, which is used while hiding + * Action Button + * + * @param animation one of the {@link Animations}, which is to be used while + * hiding Action Button + */ + public void setHideAnimation(Animations animation) { + setHideAnimation(Animations.load(getContext(), animation.animResId)); + } + + public void removeHideAnimation() { + setHideAnimation(Animations.NONE); + Log.v(LOG_TAG, "Hide animation removed"); + } + + /** + * Adds additional actions on motion events: + * 1. Changes the Action Button {@link #state} to {@link State#PRESSED} + * on {@link android.view.MotionEvent#ACTION_DOWN} + * 2. Changes the Action Button {@link #state} to {@link State#NORMAL} + * on {@link android.view.MotionEvent#ACTION_UP} + * + * @param event motion event + * @return true if event was handled, otherwise false + */ + @SuppressWarnings("all") + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + super.onTouchEvent(event); + final int action = event.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + Log.v(LOG_TAG, "Motion event action down detected"); + setState(State.PRESSED); + return true; + case MotionEvent.ACTION_UP: + Log.v(LOG_TAG, "Motion event action up detected"); + setState(State.NORMAL); + return true; + default: + Log.v(LOG_TAG, "Unrecognized motion event detected"); + return false; + } + } + + /** + * Adds additional checking whether animation is null before starting to play it + * + * @param animation animation to play + */ + @SuppressWarnings("all") + @Override + public void startAnimation(Animation animation) { + if (animation != null) { + super.startAnimation(animation); + } + } + + /** + * Resets the paint to its default values and sets initial flags to it + *

+ * Use this method before drawing the new element of the view + */ + protected final void resetPaint() { + paint.reset(); + paint.setFlags(Paint.ANTI_ALIAS_FLAG); + Log.v(LOG_TAG, "Paint reset"); + } + + /** + * Draws the elements of the Action Button + * + * @param canvas canvas, on which the drawing is to be performed + */ + @SuppressWarnings("all") + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + Log.v(LOG_TAG, "Action Button onDraw called"); + drawCircle(canvas); + if (hasElevation()) { + drawElevation(); + } + if (hasStroke()) { + drawStroke(canvas); + } + if (hasImage()) { + drawImage(canvas); + } + } + + /** + * Draws the main circle of the Action Button and calls + * {@link #drawShadow()} to draw the shadow if present + * + * @param canvas canvas, on which circle is to be drawn + */ + protected void drawCircle(Canvas canvas) { + resetPaint(); + if (hasShadow()) { + drawShadow(); + } + paint.setStyle(Paint.Style.FILL); + paint.setColor(getState() == State.PRESSED ? getButtonColorPressed() : getButtonColor()); + canvas.drawCircle(calculateCenterX(), calculateCenterY(), calculateCircleRadius(), paint); + Log.v(LOG_TAG, "Circle drawn"); + } + + /** + * Calculates the X-axis center coordinate of the entire view + * + * @return X-axis center coordinate of the entire view + */ + protected float calculateCenterX() { + final float centerX = getMeasuredWidth() / 2; + Log.v(LOG_TAG, "Calculated center X = " + centerX); + return centerX; + } + + /** + * Calculates the Y-axis center coordinate of the entire view + * + * @return Y-axis center coordinate of the entire view + */ + protected float calculateCenterY() { + final float centerY = getMeasuredHeight() / 2; + Log.v(LOG_TAG, "Calculated center Y = " + centerY); + return centerY; + } + + /** + * Calculates the radius of the main circle + * + * @return radius of the main circle + */ + protected final float calculateCircleRadius() { + final float circleRadius = getButtonSize() / 2; + Log.v(LOG_TAG, "Calculated circle circleRadius = " + circleRadius); + return circleRadius; + } + + /** + * Draws the shadow if view elevation is not enabled + */ + protected void drawShadow() { + paint.setShadowLayer(getShadowRadius(), getShadowXOffset(), getShadowYOffset(), getShadowColor()); + Log.v(LOG_TAG, "Shadow drawn"); + } + + /** + * Draws the elevation around the main circle + *

+ * Uses the stroke corrective, which helps to avoid the elevation overlapping issue + */ + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + protected void drawElevation() { + final int strokeWeightCorrective = (int) (getStrokeWidth() / 1.5f); + final int width = getWidth() - strokeWeightCorrective; + final int height = getHeight() - strokeWeightCorrective; + final ViewOutlineProvider outlineProvider = new ActionButtonOutlineProvider(width, height); + setOutlineProvider(outlineProvider); + Log.v(LOG_TAG, "Elevation drawn"); + } + + /** + * Checks whether view elevation is enabled + * + * @return true if view elevation enabled, otherwise false + */ + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + private boolean hasElevation() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && getElevation() > 0.0f; + } + + /** + * Draws stroke around the main circle + * + * @param canvas canvas, on which circle is to be drawn + */ + protected void drawStroke(Canvas canvas) { + resetPaint(); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(getStrokeWidth()); + paint.setColor(getStrokeColor()); + canvas.drawCircle(calculateCenterX(), calculateCenterY(), calculateCircleRadius(), paint); + Log.v(LOG_TAG, "Stroke drawn"); + } + + /** + * Draws the image centered inside the view + * + * @param canvas canvas, on which circle is to be drawn + */ + protected void drawImage(Canvas canvas) { + final int startPointX = (int) (calculateCenterX() - getImageSize() / 2); + final int startPointY = (int) (calculateCenterY() - getImageSize() / 2); + final int endPointX = (int) (startPointX + getImageSize()); + final int endPointY = (int) (startPointY + getImageSize()); + getImage().setBounds(startPointX, startPointY, endPointX, endPointY); + getImage().draw(canvas); + Log.v(LOG_TAG, String.format("Image drawn on canvas with coordinates: startPointX = %s, startPointY = %s, " + + "endPointX = %s, endPointY = %s", startPointX, startPointY, endPointX, endPointY)); + } + + /** + * Sets the measured dimension for the entire view + * + * @param widthMeasureSpec horizontal space requirements as imposed by the parent. + * The requirements are encoded with + * {@link android.view.View.MeasureSpec} + * @param heightMeasureSpec vertical space requirements as imposed by the parent. + * The requirements are encoded with + * {@link android.view.View.MeasureSpec} + */ + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + Log.v(LOG_TAG, "Action Button onMeasure called"); + setMeasuredDimension(calculateMeasuredWidth(), calculateMeasuredHeight()); + Log.v(LOG_TAG, String.format("View size measured with: height = %s, width = %s", getHeight(), getWidth())); + } + + /** + * Calculates the measured width in actual pixels for the entire view + * + * @return measured width in actual pixels for the entire view + */ + private int calculateMeasuredWidth() { + final int measuredWidth = getButtonSize() + calculateShadowWidth() + calculateStrokeWeight(); + Log.v(LOG_TAG, "Calculated measured width = " + measuredWidth); + return measuredWidth; + } + + /** + * Calculates the measured height in actual pixels for the entire view + * + * @return measured width in actual pixels for the entire view + */ + private int calculateMeasuredHeight() { + final int measuredHeight = getButtonSize() + calculateShadowHeight() + calculateStrokeWeight(); + Log.v(LOG_TAG, "Calculated measured height = " + measuredHeight); + return measuredHeight; + } + + /** + * Calculates shadow width in actual pixels + * + * @return shadow width in actual pixels + */ + private int calculateShadowWidth() { + final int shadowWidth = hasShadow() ? (int) ((getShadowRadius() + Math.abs(getShadowXOffset())) * 2) : 0; + Log.v(LOG_TAG, "Calculated shadow width = " + shadowWidth); + return shadowWidth; + } + + /** + * Calculates shadow height in actual pixels + * + * @return shadow height in actual pixels + */ + private int calculateShadowHeight() { + final int shadowHeight = hasShadow() ? (int) ((getShadowRadius() + Math.abs(getShadowYOffset())) * 2) : 0; + Log.v(LOG_TAG, "Calculated shadow height = " + shadowHeight); + return shadowHeight; + } + + /** + * Calculates the stroke weight in actual pixels + * * + * @return stroke weight in actual pixels + */ + private int calculateStrokeWeight() { + final int strokeWeight = (int) (getStrokeWidth() * 2.0f); + Log.v(LOG_TAG, "Calculated stroke weight is: " + strokeWeight); + return strokeWeight; + } + + /** + * Determines the Action Button types + */ + public enum Type { + + /** + * Action Button default (56dp) type + */ + DEFAULT { + @Override + int getId() { + return 0; + } + + @Override + float getSize(Context context) { + return MetricsConverter.dpToPx(context, 56.0f); + } + }, + + /** + * Action Button mini (40dp) type + */ + MINI { + @Override + int getId() { + return 1; + } + + @Override + float getSize(Context context) { + return MetricsConverter.dpToPx(context, 40.0f); + } + }; + + /** + * Returns an {@code id} for specific Action Button + * type, which is defined in attributes + * + * @return {@code id} for particular Action Button type, + * which is defined in attributes + */ + abstract int getId(); + + /** + * Returns the size of the specific type of the Action Button + * + * @param context context the view is running in + * @return size of the particular type of the Action Button + */ + abstract float getSize(Context context); + + /** + * Returns the Action Button type for a specific {@code id} + * + * @param id an {@code id}, for which Action Button type required + * @return Action Button type + */ + static Type forId(int id) { + for (Type type : values()) { + if (type.getId() == id) { + return type; + } + } + return DEFAULT; + } + + } + + /** + * Determines the Action Button states + */ + public enum State { + + /** + * Action Button normal state + */ + NORMAL, + + /** + * Action Button pressed state + */ + PRESSED + + } + + public enum Animations { + + /** + * None. Animation absent + */ + NONE (0), + + /** + * Fade in animation + */ + FADE_IN (R.anim.fab_fade_in), + + /** + * Fade out animation + */ + FADE_OUT (R.anim.fab_fade_out), + + /** + * Scale up animation + */ + SCALE_UP (R.anim.fab_scale_up), + + /** + * Scale down animation + */ + SCALE_DOWN (R.anim.fab_scale_down), + + /** + * Roll from down animation + */ + ROLL_FROM_DOWN (R.anim.fab_roll_from_down), + + /** + * Roll to down animation + */ + ROLL_TO_DOWN (R.anim.fab_roll_to_down), + + /** + * Roll from right animation + */ + ROLL_FROM_RIGHT (R.anim.fab_roll_from_right), + + /** + * Roll to right animation + */ + ROLL_TO_RIGHT (R.anim.fab_roll_to_right), + + /** + * Jump from down animation + */ + JUMP_FROM_DOWN (R.anim.fab_jump_from_down), + + /** + * Jump to down animation + */ + JUMP_TO_DOWN (R.anim.fab_jump_to_down), + + /** + * Jump from right animation + */ + JUMP_FROM_RIGHT (R.anim.fab_jump_from_right), + + /** + * Jump to right animation + */ + JUMP_TO_RIGHT (R.anim.fab_jump_to_right); + + /** + * Correspondent animation resource id + */ + final int animResId; + + private Animations(int animResId) { + this.animResId = animResId; + } + + /** + * Loads an animation from animation resource id + * + * @param context context the view is running in + * @param animResId resource id of the animation, which is to be loaded + * @return loaded animation + */ + protected static Animation load(Context context, int animResId) { + return animResId == NONE.animResId ? null : AnimationUtils.loadAnimation(context, animResId); + } + + } + +} diff --git a/eclipse-compile/fab/java/com/software/shell/fab/ActionButtonOutlineProvider.java b/eclipse-compile/fab/java/com/software/shell/fab/ActionButtonOutlineProvider.java new file mode 100644 index 0000000000..d154c3998f --- /dev/null +++ b/eclipse-compile/fab/java/com/software/shell/fab/ActionButtonOutlineProvider.java @@ -0,0 +1,74 @@ +/* + * Copyright 2015 Shell Software 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. + * + * File created: 2015-02-25 19:54:28 + */ + +package com.software.shell.fab; + +import android.annotation.TargetApi; +import android.graphics.Outline; +import android.os.Build; +import android.view.View; +import android.view.ViewOutlineProvider; + +/** + * An implementation of the {@link android.view.ViewOutlineProvider} + * for Action Button + * + * Used for drawing the elevation shadow for {@code API 21 Lollipop} and higher + * + * @author Vladislav + * @version 1.0.0 + * @since 1.0.0 + */ +@TargetApi(Build.VERSION_CODES.LOLLIPOP) +class ActionButtonOutlineProvider extends ViewOutlineProvider { + + /** + * Outline provider width + */ + private int width; + + /** + * Outline provider height + */ + private int height; + + /** + * Creates an instance of the {@link com.software.shell.fab.ActionButtonOutlineProvider} + * + * @param width initial outline provider width + * @param height initial outline provider height + */ + ActionButtonOutlineProvider(int width, int height) { + this.width = width; + this.height = height; + } + + /** + * Called to get the provider to populate the Outline. This method will be called by a View + * when its owned Drawables are invalidated, when the View's size changes, or if invalidateOutline() + * is called explicitly. The input outline is empty and has an alpha of 1.0f + * + * @param view a view, which builds the outline + * @param outline an empty outline, which is to be populated + */ + @Override + public void getOutline(View view, Outline outline) { + outline.setOval(0, 0, width, height); + } + +} diff --git a/eclipse-compile/fab/java/com/software/shell/fab/FloatingActionButton.java b/eclipse-compile/fab/java/com/software/shell/fab/FloatingActionButton.java new file mode 100644 index 0000000000..196c8e7ad5 --- /dev/null +++ b/eclipse-compile/fab/java/com/software/shell/fab/FloatingActionButton.java @@ -0,0 +1,198 @@ +/* + * Copyright 2015 Shell Software 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. + * + * File created: 2015-02-16 10:56:57 + */ + +package com.software.shell.fab; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.util.Log; +import android.view.animation.Animation; + +/** + * Deprecated since version 1.0.2. Use {@link com.software.shell.fab.ActionButton} + * class instead. + * The reason is the rename of base class name from FloatingActionButton to + * ActionButton and some of the methods, which are present in this class. + *

+ * Will be removed in version 2.0.0. Please use {@link com.software.shell.fab.ActionButton} and + * methods declared there instead + * + * @author Vladislav + * @version 1.0.0 + * @since 1.0.0 + */ +@Deprecated +public class FloatingActionButton extends ActionButton{ + + private static final String LOG_TAG = "FAB"; + + public FloatingActionButton(Context context) { + super(context); + } + + public FloatingActionButton(Context context, AttributeSet attrs) { + super(context, attrs); + initActionButton(context, attrs, 0, 0); + } + + public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initActionButton(context, attrs, defStyleAttr, 0); + } + + public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + initActionButton(context, attrs, defStyleAttr, defStyleRes); + } + + /** + * Returns an animation, which is used while showing Floating Action Button + * @deprecated since version 1.0.2. Please use {@link #getShowAnimation()} instead + * + * @return animation, which is used while showing Floating Action Button + */ + @Deprecated + public Animation getAnimationOnShow() { + return getShowAnimation(); + } + + /** + * Sets the animation, which is used while showing Floating Action Button + * @deprecated since version 1.0.2. Please use + * {@link #setShowAnimation(android.view.animation.Animation)} instead + * + * @param animation animation, which is to be used while showing + * Floating Action Button + */ + @Deprecated + public void setAnimationOnShow(Animation animation) { + setShowAnimation(animation); + } + + /** + * Sets one of the {@link Animations} as animation, which is used while showing + * Floating Action Button + * @deprecated since version 1.0.2. Please use + * {@link #setShowAnimation(com.software.shell.fab.ActionButton.Animations)} instead + * + * @param animation one of the {@link Animations}, which is to be used while + * showing Floating Action Button + */ + @Deprecated + public void setAnimationOnShow(Animations animation) { + setShowAnimation(animation); + } + + /** + * Returns an animation, which is used while hiding Floating Action Button + * @deprecated since version 1.0.2. Please use {@link #getHideAnimation()} + * instead + * + * @return animation, which is used while hiding Floating Action Button + */ + @Deprecated + public Animation getAnimationOnHide() { + return getHideAnimation(); + } + + /** + * Sets the animation, which is used while hiding Floating Action Button + * @deprecated since version 1.0.2. Please use + * {@link #setHideAnimation(android.view.animation.Animation)} instead + * + * @param animation animation, which is to be used while hiding + * Floating Action Button + */ + @Deprecated + public void setAnimationOnHide(Animation animation) { + setHideAnimation(animation); + } + + /** + * Sets one of the {@link Animations} as animation, which is used while hiding + * Floating Action Button + * @deprecated since version 1.0.2. Please use + * {@link #setHideAnimation(com.software.shell.fab.ActionButton.Animations)} )} instead + * + * @param animation one of the {@link Animations}, which is to be used while + * hiding Floating Action Button + */ + @Deprecated + public void setAnimationOnHide(Animations animation) { + setHideAnimation(animation); + } + + private void initActionButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ActionButton, + defStyleAttr, defStyleRes); + try { + initType(attributes); + initShowAnimation(attributes); + initHideAnimation(attributes); + } catch (Exception e) { + Log.e(LOG_TAG, "Unable to read attr", e); + } finally { + attributes.recycle(); + } + Log.v(LOG_TAG, "Floating Action Button initialized"); + } + + private void initType(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_type)) { + final int id = attrs.getInteger(R.styleable.ActionButton_type, 0); + setType(Type.forId(id)); + Log.v(LOG_TAG, "Initialized type: " + getType()); + } + } + + /** + * Initializes the animation, which is used while showing + * Action Button + * @deprecated since 1.0.2 and will be removed in version 2.0.0. + * Use show_animation and hide_animation in XML instead + * + * @param attrs attributes of the XML tag that is inflating the view + */ + @Deprecated + private void initShowAnimation(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_animation_onShow)) { + final int animResId = attrs.getResourceId(R.styleable.ActionButton_animation_onShow, + Animations.NONE.animResId); + setShowAnimation(Animations.load(getContext(), animResId)); + } + } + + /** + * Initializes the animation, which is used while hiding or dismissing + * Action Button + * @deprecated since 1.0.2 and will be removed in version 2.0.0 + * Use show_animation and hide_animation in XML instead + * + * @param attrs attributes of the XML tag that is inflating the view + */ + @Deprecated + private void initHideAnimation(TypedArray attrs) { + if (attrs.hasValue(R.styleable.ActionButton_animation_onHide)) { + final int animResId = attrs.getResourceId(R.styleable.ActionButton_animation_onHide, + Animations.NONE.animResId); + setHideAnimation(Animations.load(getContext(), animResId)); + } + } + +} diff --git a/eclipse-compile/fab/java/com/software/shell/fab/MetricsConverter.java b/eclipse-compile/fab/java/com/software/shell/fab/MetricsConverter.java new file mode 100644 index 0000000000..c4770449c4 --- /dev/null +++ b/eclipse-compile/fab/java/com/software/shell/fab/MetricsConverter.java @@ -0,0 +1,50 @@ +/* + * Copyright 2015 Shell Software 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. + * + * File created: 2015-01-30 22:55:44 + */ + +package com.software.shell.fab; + +import android.content.Context; + +/** + * Contains utility methods for metrics conversion + * + * @author Vladislav + * @version 1.0.0 + * @since 1.0.0 + */ +public final class MetricsConverter { + + /** + * Prevents from creating {@link com.software.shell.fab.MetricsConverter} instances + */ + private MetricsConverter() { + } + + /** + * Converts the density-independent value into real pixel value based on display metrics + * + * @param context application context + * @param dp density-independent value + * @return converted real pixel value + */ + public static float dpToPx(Context context, float dp) { + final float scale = context.getResources().getDisplayMetrics().density; + return dp * scale; + } + +} diff --git a/eclipse-compile/fab/project.properties b/eclipse-compile/fab/project.properties new file mode 100644 index 0000000000..17b8e6b92f --- /dev/null +++ b/eclipse-compile/fab/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "ant.properties", and override values to adapt the script to your +# project structure. + +# Indicates whether an apk should be generated for each density. +split.density=false +# Project target. +target=android-21 +dex.force.jumbo=true +android.library=true diff --git a/eclipse-compile/fab/res/anim-v11/fab_jump_from_down.xml b/eclipse-compile/fab/res/anim-v11/fab_jump_from_down.xml new file mode 100644 index 0000000000..87095c9bc7 --- /dev/null +++ b/eclipse-compile/fab/res/anim-v11/fab_jump_from_down.xml @@ -0,0 +1,37 @@ + + + + + + + diff --git a/eclipse-compile/fab/res/anim-v11/fab_jump_from_right.xml b/eclipse-compile/fab/res/anim-v11/fab_jump_from_right.xml new file mode 100644 index 0000000000..9db4bf984f --- /dev/null +++ b/eclipse-compile/fab/res/anim-v11/fab_jump_from_right.xml @@ -0,0 +1,38 @@ + + + + + + + + diff --git a/eclipse-compile/fab/res/anim-v11/fab_jump_to_down.xml b/eclipse-compile/fab/res/anim-v11/fab_jump_to_down.xml new file mode 100644 index 0000000000..ca59b72de1 --- /dev/null +++ b/eclipse-compile/fab/res/anim-v11/fab_jump_to_down.xml @@ -0,0 +1,38 @@ + + + + + + + + diff --git a/eclipse-compile/fab/res/anim-v11/fab_jump_to_right.xml b/eclipse-compile/fab/res/anim-v11/fab_jump_to_right.xml new file mode 100644 index 0000000000..d4287e6264 --- /dev/null +++ b/eclipse-compile/fab/res/anim-v11/fab_jump_to_right.xml @@ -0,0 +1,38 @@ + + + + + + + + diff --git a/eclipse-compile/fab/res/anim-v11/fab_roll_from_down.xml b/eclipse-compile/fab/res/anim-v11/fab_roll_from_down.xml new file mode 100644 index 0000000000..438160f361 --- /dev/null +++ b/eclipse-compile/fab/res/anim-v11/fab_roll_from_down.xml @@ -0,0 +1,35 @@ + + + + + + + diff --git a/eclipse-compile/fab/res/anim-v11/fab_roll_from_right.xml b/eclipse-compile/fab/res/anim-v11/fab_roll_from_right.xml new file mode 100644 index 0000000000..0ef84e389b --- /dev/null +++ b/eclipse-compile/fab/res/anim-v11/fab_roll_from_right.xml @@ -0,0 +1,35 @@ + + + + + + + diff --git a/eclipse-compile/fab/res/anim-v11/fab_roll_to_down.xml b/eclipse-compile/fab/res/anim-v11/fab_roll_to_down.xml new file mode 100644 index 0000000000..8e8140cf93 --- /dev/null +++ b/eclipse-compile/fab/res/anim-v11/fab_roll_to_down.xml @@ -0,0 +1,36 @@ + + + + + + + + diff --git a/eclipse-compile/fab/res/anim-v11/fab_roll_to_right.xml b/eclipse-compile/fab/res/anim-v11/fab_roll_to_right.xml new file mode 100644 index 0000000000..22915225a9 --- /dev/null +++ b/eclipse-compile/fab/res/anim-v11/fab_roll_to_right.xml @@ -0,0 +1,36 @@ + + + + + + + + diff --git a/eclipse-compile/fab/res/anim-v11/fab_scale_down.xml b/eclipse-compile/fab/res/anim-v11/fab_scale_down.xml new file mode 100644 index 0000000000..ce63f0fd5f --- /dev/null +++ b/eclipse-compile/fab/res/anim-v11/fab_scale_down.xml @@ -0,0 +1,30 @@ + + + + diff --git a/eclipse-compile/fab/res/anim-v11/fab_scale_up.xml b/eclipse-compile/fab/res/anim-v11/fab_scale_up.xml new file mode 100644 index 0000000000..1d18f40544 --- /dev/null +++ b/eclipse-compile/fab/res/anim-v11/fab_scale_up.xml @@ -0,0 +1,29 @@ + + + diff --git a/eclipse-compile/fab/res/anim/fab_fade_in.xml b/eclipse-compile/fab/res/anim/fab_fade_in.xml new file mode 100644 index 0000000000..2b0ebedb7f --- /dev/null +++ b/eclipse-compile/fab/res/anim/fab_fade_in.xml @@ -0,0 +1,25 @@ + + + + diff --git a/eclipse-compile/fab/res/anim/fab_fade_out.xml b/eclipse-compile/fab/res/anim/fab_fade_out.xml new file mode 100644 index 0000000000..064ff9e45b --- /dev/null +++ b/eclipse-compile/fab/res/anim/fab_fade_out.xml @@ -0,0 +1,25 @@ + + + + diff --git a/eclipse-compile/fab/res/anim/fab_jump_from_down.xml b/eclipse-compile/fab/res/anim/fab_jump_from_down.xml new file mode 100644 index 0000000000..f41e38317f --- /dev/null +++ b/eclipse-compile/fab/res/anim/fab_jump_from_down.xml @@ -0,0 +1,36 @@ + + + + + + + diff --git a/eclipse-compile/fab/res/anim/fab_jump_from_right.xml b/eclipse-compile/fab/res/anim/fab_jump_from_right.xml new file mode 100644 index 0000000000..c9bdc0da7a --- /dev/null +++ b/eclipse-compile/fab/res/anim/fab_jump_from_right.xml @@ -0,0 +1,37 @@ + + + + + + + + diff --git a/eclipse-compile/fab/res/anim/fab_jump_to_down.xml b/eclipse-compile/fab/res/anim/fab_jump_to_down.xml new file mode 100644 index 0000000000..0649c71a04 --- /dev/null +++ b/eclipse-compile/fab/res/anim/fab_jump_to_down.xml @@ -0,0 +1,37 @@ + + + + + + + + diff --git a/eclipse-compile/fab/res/anim/fab_jump_to_right.xml b/eclipse-compile/fab/res/anim/fab_jump_to_right.xml new file mode 100644 index 0000000000..8ea8b69a3a --- /dev/null +++ b/eclipse-compile/fab/res/anim/fab_jump_to_right.xml @@ -0,0 +1,37 @@ + + + + + + + + diff --git a/eclipse-compile/fab/res/anim/fab_roll_from_down.xml b/eclipse-compile/fab/res/anim/fab_roll_from_down.xml new file mode 100644 index 0000000000..66a284f25d --- /dev/null +++ b/eclipse-compile/fab/res/anim/fab_roll_from_down.xml @@ -0,0 +1,48 @@ + + + + + + + + + diff --git a/eclipse-compile/fab/res/anim/fab_roll_from_right.xml b/eclipse-compile/fab/res/anim/fab_roll_from_right.xml new file mode 100644 index 0000000000..3c38343fcd --- /dev/null +++ b/eclipse-compile/fab/res/anim/fab_roll_from_right.xml @@ -0,0 +1,48 @@ + + + + + + + + + diff --git a/eclipse-compile/fab/res/anim/fab_roll_to_down.xml b/eclipse-compile/fab/res/anim/fab_roll_to_down.xml new file mode 100644 index 0000000000..16a6946ea9 --- /dev/null +++ b/eclipse-compile/fab/res/anim/fab_roll_to_down.xml @@ -0,0 +1,48 @@ + + + + + + + + + diff --git a/eclipse-compile/fab/res/anim/fab_roll_to_right.xml b/eclipse-compile/fab/res/anim/fab_roll_to_right.xml new file mode 100644 index 0000000000..420734f2b8 --- /dev/null +++ b/eclipse-compile/fab/res/anim/fab_roll_to_right.xml @@ -0,0 +1,48 @@ + + + + + + + + + diff --git a/eclipse-compile/fab/res/anim/fab_scale_down.xml b/eclipse-compile/fab/res/anim/fab_scale_down.xml new file mode 100644 index 0000000000..e0dd6bea64 --- /dev/null +++ b/eclipse-compile/fab/res/anim/fab_scale_down.xml @@ -0,0 +1,41 @@ + + + + + + + diff --git a/eclipse-compile/fab/res/anim/fab_scale_up.xml b/eclipse-compile/fab/res/anim/fab_scale_up.xml new file mode 100644 index 0000000000..956f6ed79d --- /dev/null +++ b/eclipse-compile/fab/res/anim/fab_scale_up.xml @@ -0,0 +1,42 @@ + + + + + + + + \ No newline at end of file diff --git a/eclipse-compile/fab/res/drawable-hdpi/fab_plus_icon.png b/eclipse-compile/fab/res/drawable-hdpi/fab_plus_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b4358ce2015d3f303e8f27927b607723cdb56368 GIT binary patch literal 1104 zcmaJ=TWHfz7*4%SywnP!%o}If9CNHqlU}yQ)vjw=Et)yI!sgr3{)RP2cl0RBAZWMUSx>AsfaL7<~n__h9u|0_kI6&{{KItogIfZ zZ`iqkqNvTu!$OLTb@sP@9r?ebCML*GjpIGI3uSRZG9eXJPzHjeCiTG-l$62K&tNM> zt)|s<5AG3<@-osql8x~cHG{Azsx?wHB)K1Akb!-w9;UxMoTh=Qgz4^p=oO6^%&CWm zOxQKlk(P)0<&Z*04uaMqPXsiGB~a8(=@wrM(@VNMncLe84VECdKTQ8N)gyL-7&0LU zczkZz%d#LC^sxRwFvvCm&dYL)m%KqY>*oVOo@)ln4^5((N|sLviRD;i6{d3-8$81l z3I$KW=Rsy4!-hg3TZ7}=1mU&@bu1O#x>Z|N5TGTSs)1Fc16xtbpga!K#Od!NXvT`H zZY`&YB#bFa2E%&1_L0g!QT#tt(^k+HPQgEZ|0!&x2Mx%ipoQ|LObVB+wL=+v%!Cp~ zW*VVWoxMa|I;lHK^k6RQBSl$YqEb#xCq%g)VQA?y;vUZA%s_jSqFw?Ivk!SKWLgxe~KUA(}3} z$^2Ygj6CUGb!pPMGymfDu-8%L+8CQh=e}3PZ=KsM)O=n0{!8blBX&T*J)V zHb;G9%g2cGYbi8xxA#?)FgH1Wj17we)#o3q8CaXiuF6i-PVFg8Tr2&UZhN$=dvxr< z!d1unr~Zr8C%{>*?xpLoi{AIV@#ZHdIG9Y1AD=Yyi&v=6K(@WNd)vj$?SG8qyg%w{kP0qH^B_}3lHk*P| z6y|Wqm`{6DK?PA!#0NncOk{8BUZzi?FFwr6gUAGNo@{OBgEb^M7ryWN|MUOfx!jXF z+)&$GOAtguqFYGgvB~~6*WmyALU0)mJ5el)dSO2*hz20SGRy%op^5__4Mch5)I8`U zh-ym7WKlMGjF+HFi#CR~R2{PkqBCUaqLc@S%z*(#3sPU7KBq`U4pM!-q${aM!JyJT zYJlF+R7M)jO97b*9U?m|9t)@diKL|tX(n$4sa0Jb&+To7B3B_OAEefj$|ifrC^P`+ zqdiW^#j+&F(X7|UaqL0T?PA@G3%{I`_3}QBcXyD*hr-bext~u9@nS5z3Q~gz={&;} z3I)30p`kIruz^6p)^NL>7~wQWG$dM1&1@+t2*8vKMMnzMNLx|N!C@4naHeZVQ1!B` zW){nY3&vQY&akx0K2iyoO#UCLs%5l^(qKK`e+rwK5gjmTV8UTT!j0>1u|w&6)Bqxa zMh3#6QWbj!A%f;0)X8WsN4E7TnhXo(fmM7m$tN@uiJAlwLXg4=w4%toFW}`O9iEP` z-xFuqnAacmxP&OnMSSsiG!hG!xB`@hRiL2~S6=7(D{^fss5*`;07E$q3k;~v@7`w55HM+Eg-D6M7w#AFG@qvcjZeUwe^Rp>@C8iTXIAgub z{aRTGRXeM;S5MBqdNOv&@%T#D?s{;4W9~Y2b?Rbw&CegcYtGuamD``Iw=Q?iOnf_k z&cC?tWmQY#N3*_e%hBIAZqY+`+8pC&bbojAkGOm0&t^w>znsJ3Di0rwt-# z#0x?s8c%*6Jg5pG5osGDgs31Ysd%U+ctG$XJV@Nx?v@8@GBfw@ob#P~zwaJvN;b@^ zTwDnNm=|x9Q>5j+Z`MrmZ<+q{C}|eqSSxNu8Jt&a2qGG4hg959I$#PaT6gXdtO1~c z*3+%HHL+Pzk-;h+hII{#umPyq;982>2{F|UJ9INlf4MVEQ@R$WTLK9_VMSq9Z|t#Q zb5Am@_H?Qtjowg8)wmK7Fd$Ya*Vtn^k{hNAx)SMo(;Q6|Ahl zF)A+zlqj--KOl<2I?BfjK8`1^$OwKZAWFXVRPmunG+WC^DY?EFi;Ti_7Gq1|xO_g( z=Brp_cW^=|6!J8DK87F|r`yDe%b3oJl7b8!)z&SnBa`wJm3GvH!!&U^xdp?Tk~N*; zF_8n~T*cx9miM+)0wxmwhZ@Ed+QBLK$L~LdopiSaxfFCzm#vb-Wmb5hEGcS31tU9+ z(4NvMHf0e;P8L~Iv{|H9x9FyZ^3Iw9K9P{(rh^qzg>gAd69rb+HOcP}iFJZ67713> z3qs5v6zcd$P?W{s`j{9B@FlK{)Gh;>xWv`|aO=x*y;3kN5?O|}z87lsHZrKfmL|cp4O_A#Hx>IFK22+I(O;YVPDeGhV#)rt27>Ub~wEOx~ z-(clEenIb&kEcc&a%;^)LnpUP%o!cKd1B)IN};z}oBihgCF@(YH9q&(+l#k9pU*8n za`*b)!?|gNi}m&N_oV~-Pt%ow$>*mvl$$+R)wigy3cx`I)b_neCx5okOs1{> z;j)#(m!6$z+zM_&mdOO#B2Rli{1`qv?elzhoB#2`O_#^!zRVsUYCItC>L2WVu=#y; zQ3&h+KVD?UZaf)X%^ch`a4vXj`=oDi0lxCFQGiyAS;aN*rrr literal 0 HcmV?d00001 diff --git a/eclipse-compile/fab/res/drawable-xxhdpi/fab_plus_icon.png b/eclipse-compile/fab/res/drawable-xxhdpi/fab_plus_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..569b089f47cef2be0b82fdfe7a4ad516515e61d5 GIT binary patch literal 1182 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`f(~1RD^r68eAMwS&*t9 zlvv ztM~P_^2{qPNz6-5^>ndS0-B(gnVDkc=4#+-Vq)g(XkqMXXy|I<1m>8TSejY7IGQ+F z!t}c2Czs}?=9R$orXcjX;M5CB3b_S9n_W_iGRsm^+=}vZ6~JD$%Eav!N1WzC^`_u< zixW=0`as9%gCZ6wqG3Y7)B|F|lP!<~Pxz^Mz|>v@Ox7I!_g^wFFba9PIEGZ*dUIz# z=OG6X_5@`{X>aulhB5Bq1p?gBZ|58}yu!MssaN5cFsq_Mi?ST&&$lrOl;Z@fI#LF*O&klI*m7B9M|D9=d+5|;j zpi)K_sCprwrmsvd!ZuI0iF_iyBJTWz>%8ld<+7q)&UKQNs_DI|@JO;;=fdlxKH1y4 zoB69I>3)0hz@js1v*KU%1&Q(NOuscBR=Tn;*?E`8PrYj;+ZKvVy{C8OlI4rJfoJDU z-ZI$)=qeVd(^x!!?z_UhU{9KU<*iRAwr;ggJNd`7RT9}Pj9Jn1n0Oc*Om&xV3MXs? Ol^C9`elF{r5}E*keu5YP literal 0 HcmV?d00001 diff --git a/eclipse-compile/fab/res/drawable-xxxhdpi/fab_plus_icon.png b/eclipse-compile/fab/res/drawable-xxxhdpi/fab_plus_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..90a1d16dcf5922b85e7d4067a3c7c297a73e7ee3 GIT binary patch literal 1105 zcmaJ=PiWIn7=N3cZo`2GK^zE=45orjnzYT@ux{;|)>TZIZDG9#OOv-Xbjgd!o6UOA zAqskNc+-;u58ieY1P_8RVJA;R(OujSFTzgFiw9r2{@GzQBzfAugBsuH zA)be#$nue>DDu~!5aIYD+ww(M38qSjEpc4EUT5oJ z7CTEEACJd<4M7M}M9^Kei0TC`cdV@-BUf__n;6)FzM@*eD$b9xHU)M7zhIcG{LMI*pGk+U*W)>(~3|EA&ci<>XY!`}%A5+sGO` zo4i%~a{q_WcW?XE_uZk#m!so@&t9w_{%!;S7zCgXKmY<@4S;h1^n;{Z8~FV9&7%wB z$rHD`M)u&-^nU&=sqBn?2zUcSzSKr>Dm{Pcshv!BamTc~#>nR0&X(GL;$C3m#_hE} Y@bJ%>kLxcFf6|0NE|ZrxXBHm(1D7{KjsO4v literal 0 HcmV?d00001 diff --git a/eclipse-compile/fab/res/values-sw600dp/dimens.xml b/eclipse-compile/fab/res/values-sw600dp/dimens.xml new file mode 100644 index 0000000000..3ca9bdfce2 --- /dev/null +++ b/eclipse-compile/fab/res/values-sw600dp/dimens.xml @@ -0,0 +1,23 @@ + + + + + + 24dp + diff --git a/eclipse-compile/fab/res/values/attrs.xml b/eclipse-compile/fab/res/values/attrs.xml new file mode 100644 index 0000000000..bdd08225a7 --- /dev/null +++ b/eclipse-compile/fab/res/values/attrs.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eclipse-compile/fab/res/values/colors.xml b/eclipse-compile/fab/res/values/colors.xml new file mode 100644 index 0000000000..60ca1a0bbb --- /dev/null +++ b/eclipse-compile/fab/res/values/colors.xml @@ -0,0 +1,86 @@ + + + + + + + #f44336 + #b71c1c + + #e91e63 + #880e4f + + #9c27b0 + #4a148c + + #673ab7 + #311b92 + + #3f51b5 + #1a237e + + #2196f3 + #0d47a1 + + #03a9f4 + #01579b + + #00bcd4 + #006064 + + #009688 + #004d40 + + #4caf50 + #1b5e20 + + #8bc34a + #33691e + + #cddc39 + #827717 + + #ffeb3b + #f57f17 + + #ffc107 + #ff6f00 + + #ff9800 + #e65100 + + #ff5722 + #bf360c + + #795548 + #3e2723 + + #9e9e9e + #212121 + + #607d8b + #263238 + + #000000 + + #ffffff + diff --git a/eclipse-compile/fab/res/values/dimens.xml b/eclipse-compile/fab/res/values/dimens.xml new file mode 100644 index 0000000000..06d5dccfcd --- /dev/null +++ b/eclipse-compile/fab/res/values/dimens.xml @@ -0,0 +1,24 @@ + + + + + + 16dp + +