mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2025-04-19 10:32:46 +02:00
DroidFish: Use the TourGuide library to display usage hints the first
time the program is started.
This commit is contained in:
parent
88074f5327
commit
cbba46a6d5
DroidFish
res
drawable-hdpi
drawable-mdpi
drawable-xhdpi
drawable-xxhdpi
drawable-xxxhdpi
layout-land
layout
raw
values-v14
values
xml
src
net/i2p/android/ext/floatingactionbutton
org/petero/droidfish
tourguide/tourguide
BIN
DroidFish/res/drawable-hdpi/fab_bg_mini.png
Normal file
BIN
DroidFish/res/drawable-hdpi/fab_bg_mini.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 7.8 KiB |
BIN
DroidFish/res/drawable-hdpi/fab_bg_normal.png
Normal file
BIN
DroidFish/res/drawable-hdpi/fab_bg_normal.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 9.7 KiB |
BIN
DroidFish/res/drawable-mdpi/fab_bg_mini.png
Normal file
BIN
DroidFish/res/drawable-mdpi/fab_bg_mini.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 5.8 KiB |
BIN
DroidFish/res/drawable-mdpi/fab_bg_normal.png
Normal file
BIN
DroidFish/res/drawable-mdpi/fab_bg_normal.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 6.9 KiB |
BIN
DroidFish/res/drawable-xhdpi/drop_shadow.9.png
Normal file
BIN
DroidFish/res/drawable-xhdpi/drop_shadow.9.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 690 B |
BIN
DroidFish/res/drawable-xhdpi/fab_bg_mini.png
Normal file
BIN
DroidFish/res/drawable-xhdpi/fab_bg_mini.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 9.9 KiB |
BIN
DroidFish/res/drawable-xhdpi/fab_bg_normal.png
Normal file
BIN
DroidFish/res/drawable-xhdpi/fab_bg_normal.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 13 KiB |
BIN
DroidFish/res/drawable-xxhdpi/fab_bg_mini.png
Normal file
BIN
DroidFish/res/drawable-xxhdpi/fab_bg_mini.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 6.4 KiB |
BIN
DroidFish/res/drawable-xxhdpi/fab_bg_normal.png
Normal file
BIN
DroidFish/res/drawable-xxhdpi/fab_bg_normal.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 8.3 KiB |
BIN
DroidFish/res/drawable-xxxhdpi/fab_bg_mini.png
Normal file
BIN
DroidFish/res/drawable-xxxhdpi/fab_bg_mini.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 8.8 KiB |
BIN
DroidFish/res/drawable-xxxhdpi/fab_bg_normal.png
Normal file
BIN
DroidFish/res/drawable-xxxhdpi/fab_bg_normal.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 12 KiB |
@ -26,6 +26,7 @@
|
|||||||
layout="@layout/title">
|
layout="@layout/title">
|
||||||
</include>
|
</include>
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/buttons"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -25,49 +25,55 @@
|
|||||||
android:paddingTop="1dp">
|
android:paddingTop="1dp">
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/status"
|
android:id="@+id/status"
|
||||||
android:layout_width="0dp"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:includeFontPadding="true"
|
android:includeFontPadding="true"
|
||||||
android:fontFamily="monospace"
|
android:fontFamily="monospace"
|
||||||
android:typeface="monospace"
|
android:typeface="monospace"
|
||||||
android:textSize="12sp"/>
|
android:textSize="12sp"/>
|
||||||
<ImageButton
|
<LinearLayout
|
||||||
android:id="@+id/custom3Button"
|
android:id="@+id/buttons"
|
||||||
android:contentDescription="@string/buttonDesc_custom3"
|
android:orientation="horizontal"
|
||||||
android:layout_width="36dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="32dp">
|
android:layout_height="wrap_content">
|
||||||
</ImageButton>
|
<ImageButton
|
||||||
<ImageButton
|
android:id="@+id/custom3Button"
|
||||||
android:id="@+id/custom2Button"
|
android:contentDescription="@string/buttonDesc_custom3"
|
||||||
android:contentDescription="@string/buttonDesc_custom2"
|
android:layout_width="36dp"
|
||||||
android:layout_width="36dp"
|
android:layout_height="32dp">
|
||||||
android:layout_height="32dp">
|
</ImageButton>
|
||||||
</ImageButton>
|
<ImageButton
|
||||||
<ImageButton
|
android:id="@+id/custom2Button"
|
||||||
android:id="@+id/custom1Button"
|
android:contentDescription="@string/buttonDesc_custom2"
|
||||||
android:contentDescription="@string/buttonDesc_custom1"
|
android:layout_width="36dp"
|
||||||
android:layout_width="36dp"
|
android:layout_height="32dp">
|
||||||
android:layout_height="32dp">
|
</ImageButton>
|
||||||
</ImageButton>
|
<ImageButton
|
||||||
<ImageButton
|
android:id="@+id/custom1Button"
|
||||||
android:id="@+id/modeButton"
|
android:contentDescription="@string/buttonDesc_custom1"
|
||||||
android:contentDescription="@string/buttonDesc_mode"
|
android:layout_width="36dp"
|
||||||
android:layout_width="36dp"
|
android:layout_height="32dp">
|
||||||
android:layout_height="32dp">
|
</ImageButton>
|
||||||
</ImageButton>
|
<ImageButton
|
||||||
<ImageButton
|
android:id="@+id/modeButton"
|
||||||
android:id="@+id/undoButton"
|
android:contentDescription="@string/buttonDesc_mode"
|
||||||
android:contentDescription="@string/buttonDesc_back"
|
android:layout_width="36dp"
|
||||||
android:layout_width="36dp"
|
android:layout_height="32dp">
|
||||||
android:layout_height="32dp">
|
</ImageButton>
|
||||||
</ImageButton>
|
<ImageButton
|
||||||
<ImageButton
|
android:id="@+id/undoButton"
|
||||||
android:id="@+id/redoButton"
|
android:contentDescription="@string/buttonDesc_back"
|
||||||
android:contentDescription="@string/buttonDesc_forward"
|
android:layout_width="36dp"
|
||||||
android:layout_width="36dp"
|
android:layout_height="32dp">
|
||||||
android:layout_height="32dp">
|
</ImageButton>
|
||||||
</ImageButton>
|
<ImageButton
|
||||||
|
android:id="@+id/redoButton"
|
||||||
|
android:contentDescription="@string/buttonDesc_forward"
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="32dp">
|
||||||
|
</ImageButton>
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<view
|
<view
|
||||||
class="org.petero.droidfish.MyRelativeLayout"
|
class="org.petero.droidfish.MyRelativeLayout"
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
layout="@layout/title">
|
layout="@layout/title">
|
||||||
</include>
|
</include>
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/buttons"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
40
DroidFish/res/layout/tooltip.xml
Normal file
40
DroidFish/res/layout/tooltip.xml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!--<View-->
|
||||||
|
<!--android:layout_width="wrap_content"-->
|
||||||
|
<!--android:layout_height="5dp"-->
|
||||||
|
<!--android:background="@drawable/shadow_upward" />-->
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/toolTip_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:background="#e74c3c"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="10dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="Default Title"
|
||||||
|
android:textColor="@color/White"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/description"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="Default Description"
|
||||||
|
android:textColor="@color/White" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -240,6 +240,12 @@
|
|||||||
<li>
|
<li>
|
||||||
Syzygy tablebases probing code, Copyright © 2011-2013 Ronald de Man.
|
Syzygy tablebases probing code, Copyright © 2011-2013 Ronald de Man.
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://github.com/worker8/TourGuide">TourGuide</a> library, Copyright © 2015 Tan Jun Rong.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://github.com/Tesla-Redux/android-floating-action-button">Floating action button</a> library, Copyright © 2014 str4d and Jerzy Chalupski.
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h3>Translations</h3>
|
<h3>Translations</h3>
|
||||||
|
7
DroidFish/res/values-v14/colors.xml
Normal file
7
DroidFish/res/values-v14/colors.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="default_normal">@android:color/holo_blue_dark</color>
|
||||||
|
<color name="default_pressed">@android:color/holo_blue_light</color>
|
||||||
|
<color name="default_disabled">@android:color/darker_gray</color>
|
||||||
|
<color name="White">#FFFFFF</color>
|
||||||
|
</resources>
|
39
DroidFish/res/values/attrs.xml
Normal file
39
DroidFish/res/values/attrs.xml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<declare-styleable name="FloatingActionButton">
|
||||||
|
<attr name="fab_colorPressed" format="color"/>
|
||||||
|
<attr name="fab_colorDisabled" format="color"/>
|
||||||
|
<attr name="fab_colorNormal" format="color"/>
|
||||||
|
<attr name="fab_icon" format="reference"/>
|
||||||
|
<attr name="fab_size" format="enum">
|
||||||
|
<enum name="normal" value="0"/>
|
||||||
|
<enum name="mini" value="1"/>
|
||||||
|
</attr>
|
||||||
|
<attr name="fab_title" format="string"/>
|
||||||
|
<attr name="fab_stroke_visible" format="boolean"/>
|
||||||
|
</declare-styleable>
|
||||||
|
<declare-styleable name="AddFloatingActionButton">
|
||||||
|
<attr name="fab_plusIconColor" format="color"/>
|
||||||
|
</declare-styleable>
|
||||||
|
<declare-styleable name="FloatingActionsMenu">
|
||||||
|
<attr name="fab_addButtonColorPressed" format="color"/>
|
||||||
|
<attr name="fab_addButtonColorNormal" format="color"/>
|
||||||
|
<attr name="fab_addButtonSize" format="enum">
|
||||||
|
<enum name="normal" value="0"/>
|
||||||
|
<enum name="mini" value="1"/>
|
||||||
|
</attr>
|
||||||
|
<attr name="fab_addButtonPlusIconColor" format="color"/>
|
||||||
|
<attr name="fab_addButtonStrokeVisible" format="boolean"/>
|
||||||
|
<attr name="fab_labelStyle" format="reference"/>
|
||||||
|
<attr name="fab_labelsPosition" format="enum">
|
||||||
|
<enum name="left" value="0"/>
|
||||||
|
<enum name="right" value="1"/>
|
||||||
|
</attr>
|
||||||
|
<attr name="fab_expandDirection" format="enum">
|
||||||
|
<enum name="up" value="0"/>
|
||||||
|
<enum name="down" value="1"/>
|
||||||
|
<enum name="left" value="2"/>
|
||||||
|
<enum name="right" value="3"/>
|
||||||
|
</attr>
|
||||||
|
</declare-styleable>
|
||||||
|
</resources>
|
7
DroidFish/res/values/colors.xml
Normal file
7
DroidFish/res/values/colors.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="default_normal">#ff0099cc</color><!-- android.R.color.holo_blue_dark -->
|
||||||
|
<color name="default_pressed">#ff33b5e5</color><!-- android.R.color.holo_blue_light -->
|
||||||
|
<color name="default_disabled">#aaa</color><!-- android.R.color.darker_gray -->
|
||||||
|
<color name="White">#FFFFFF</color>
|
||||||
|
</resources>
|
17
DroidFish/res/values/dimens.xml
Normal file
17
DroidFish/res/values/dimens.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<resources>
|
||||||
|
<dimen name="fab_size_normal">56dp</dimen>
|
||||||
|
<dimen name="fab_size_mini">40dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="fab_icon_size">24dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="fab_plus_icon_size">14dp</dimen>
|
||||||
|
<dimen name="fab_plus_icon_stroke">2dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="fab_shadow_offset">3dp</dimen>
|
||||||
|
<dimen name="fab_shadow_radius">9dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="fab_stroke_width">1dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="fab_actions_spacing">16dp</dimen>
|
||||||
|
<dimen name="fab_labels_margin">8dp</dimen>
|
||||||
|
</resources>
|
5
DroidFish/res/values/ids.xml
Normal file
5
DroidFish/res/values/ids.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<item name="fab_expand_menu_button" type="id"/>
|
||||||
|
<item name="fab_label" type="id"/>
|
||||||
|
</resources>
|
@ -413,6 +413,20 @@ you are not actively using the program.\
|
|||||||
<string name="prefs_rtbPath_summary">Directory where Syzygy tablebases are installed. Leave blank to use default directory</string>
|
<string name="prefs_rtbPath_summary">Directory where Syzygy tablebases are installed. Leave blank to use default directory</string>
|
||||||
<string name="prefs_rtbPathNet_title">Syzygy Network Directory</string>
|
<string name="prefs_rtbPathNet_title">Syzygy Network Directory</string>
|
||||||
<string name="prefs_rtbPathNet_summary">Directory for network engines where Syzygy tablebases are installed.</string>
|
<string name="prefs_rtbPathNet_summary">Directory for network engines where Syzygy tablebases are installed.</string>
|
||||||
|
<string name="prefs_guideShowOnStart_title">Startup Guide</string>
|
||||||
|
<string name="prefs_guideShowOnStart_summary">Show the startup guide the next time the program is started.</string>
|
||||||
|
<string name="tour_leftMenu_title">Left Menu</string>
|
||||||
|
<string name="tour_leftMenu_desc">To open the left menu, tap on the left side of the title bar or swipe from the left side of the screen towards the right side.</string>
|
||||||
|
<string name="tour_rightMenu_title">Right Menu</string>
|
||||||
|
<string name="tour_rightMenu_desc">To open the right menu, tap on the right side of the title bar or swipe from the right side of the screen towards the left side.</string>
|
||||||
|
<string name="tour_chessBoard_title">Chess Board</string>
|
||||||
|
<string name="tour_chessBoard_desc">Touch and hold the chess board to open the tools menu.</string>
|
||||||
|
<string name="tour_buttons_title">Buttons</string>
|
||||||
|
<string name="tour_buttons_desc">Tap a button to invoke its action. Touch and hold a button to open a menu containing secondary actions. To configure button actions go to Left Menu > Settings > Behavior > Configure Buttons.</string>
|
||||||
|
<string name="tour_moveList_title">Move List</string>
|
||||||
|
<string name="tour_moveList_desc">Tap a move in the move list to set the chess board to the corresponding position. Touch and hold the move list to open the Edit Game menu.</string>
|
||||||
|
<string name="tour_analysis_title">Analysis information</string>
|
||||||
|
<string name="tour_analysis_desc">When the engine is thinking, touch and hold the analysis information to open the Analysis menu.</string>
|
||||||
<string name="buttonDesc_custom1">@string/prefs_custom_button_1</string>
|
<string name="buttonDesc_custom1">@string/prefs_custom_button_1</string>
|
||||||
<string name="buttonDesc_custom2">@string/prefs_custom_button_2</string>
|
<string name="buttonDesc_custom2">@string/prefs_custom_button_2</string>
|
||||||
<string name="buttonDesc_custom3">@string/prefs_custom_button_3</string>
|
<string name="buttonDesc_custom3">@string/prefs_custom_button_3</string>
|
||||||
|
@ -518,6 +518,12 @@
|
|||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:title="@string/prefs_other">
|
android:title="@string/prefs_other">
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:key="guideShowOnStart"
|
||||||
|
android:title="@string/prefs_guideShowOnStart_title"
|
||||||
|
android:summary="@string/prefs_guideShowOnStart_summary"
|
||||||
|
android:defaultValue="true">
|
||||||
|
</CheckBoxPreference>
|
||||||
<PreferenceScreen
|
<PreferenceScreen
|
||||||
android:key="bookSettings"
|
android:key="bookSettings"
|
||||||
android:title="@string/prefs_bookSettings_title"
|
android:title="@string/prefs_bookSettings_title"
|
||||||
|
@ -0,0 +1,431 @@
|
|||||||
|
package net.i2p.android.ext.floatingactionbutton;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.LinearGradient;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Paint.Style;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.Shader;
|
||||||
|
import android.graphics.Shader.TileMode;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.graphics.drawable.LayerDrawable;
|
||||||
|
import android.graphics.drawable.ShapeDrawable;
|
||||||
|
import android.graphics.drawable.ShapeDrawable.ShaderFactory;
|
||||||
|
import android.graphics.drawable.StateListDrawable;
|
||||||
|
import android.graphics.drawable.shapes.OvalShape;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Build.VERSION_CODES;
|
||||||
|
import android.support.annotation.ColorRes;
|
||||||
|
import android.support.annotation.DimenRes;
|
||||||
|
import android.support.annotation.DrawableRes;
|
||||||
|
import android.support.annotation.IntDef;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
import org.petero.droidfish.R;
|
||||||
|
|
||||||
|
public class FloatingActionButton extends ImageButton {
|
||||||
|
|
||||||
|
public static final int SIZE_NORMAL = 0;
|
||||||
|
public static final int SIZE_MINI = 1;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@IntDef({ SIZE_NORMAL, SIZE_MINI })
|
||||||
|
public @interface FAB_SIZE {
|
||||||
|
}
|
||||||
|
|
||||||
|
int mColorNormal;
|
||||||
|
int mColorPressed;
|
||||||
|
int mColorDisabled;
|
||||||
|
String mTitle;
|
||||||
|
@DrawableRes
|
||||||
|
private int mIcon;
|
||||||
|
private Drawable mIconDrawable;
|
||||||
|
private int mSize;
|
||||||
|
|
||||||
|
private float mCircleSize;
|
||||||
|
private float mShadowRadius;
|
||||||
|
private float mShadowOffset;
|
||||||
|
private int mDrawableSize;
|
||||||
|
boolean mStrokeVisible;
|
||||||
|
|
||||||
|
public FloatingActionButton(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatingActionButton(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
init(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatingActionButton(Context context, AttributeSet attrs, int defStyle) {
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
init(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(Context context, AttributeSet attributeSet) {
|
||||||
|
TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.FloatingActionButton, 0, 0);
|
||||||
|
mColorNormal = attr.getColor(R.styleable.FloatingActionButton_fab_colorNormal, getColor(R.color.default_normal));
|
||||||
|
mColorPressed = attr.getColor(R.styleable.FloatingActionButton_fab_colorPressed, getColor(R.color.default_pressed));
|
||||||
|
mColorDisabled = attr.getColor(R.styleable.FloatingActionButton_fab_colorDisabled, getColor(R.color.default_disabled));
|
||||||
|
mSize = attr.getInt(R.styleable.FloatingActionButton_fab_size, SIZE_NORMAL);
|
||||||
|
mIcon = attr.getResourceId(R.styleable.FloatingActionButton_fab_icon, 0);
|
||||||
|
mTitle = attr.getString(R.styleable.FloatingActionButton_fab_title);
|
||||||
|
mStrokeVisible = attr.getBoolean(R.styleable.FloatingActionButton_fab_stroke_visible, true);
|
||||||
|
attr.recycle();
|
||||||
|
|
||||||
|
updateCircleSize();
|
||||||
|
mShadowRadius = getDimension(R.dimen.fab_shadow_radius);
|
||||||
|
mShadowOffset = getDimension(R.dimen.fab_shadow_offset);
|
||||||
|
updateDrawableSize();
|
||||||
|
|
||||||
|
updateBackground();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDrawableSize() {
|
||||||
|
mDrawableSize = (int) (mCircleSize + 2 * mShadowRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateCircleSize() {
|
||||||
|
mCircleSize = getDimension(mSize == SIZE_NORMAL ? R.dimen.fab_size_normal : R.dimen.fab_size_mini);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSize(@FAB_SIZE int size) {
|
||||||
|
if (size != SIZE_MINI && size != SIZE_NORMAL) {
|
||||||
|
throw new IllegalArgumentException("Use @FAB_SIZE constants only!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSize != size) {
|
||||||
|
mSize = size;
|
||||||
|
updateCircleSize();
|
||||||
|
updateDrawableSize();
|
||||||
|
updateBackground();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FAB_SIZE
|
||||||
|
public int getSize() {
|
||||||
|
return mSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIcon(@DrawableRes int icon) {
|
||||||
|
if (mIcon != icon) {
|
||||||
|
mIcon = icon;
|
||||||
|
mIconDrawable = null;
|
||||||
|
updateBackground();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIconDrawable(@NonNull Drawable iconDrawable) {
|
||||||
|
if (mIconDrawable != iconDrawable) {
|
||||||
|
mIcon = 0;
|
||||||
|
mIconDrawable = iconDrawable;
|
||||||
|
updateBackground();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current Color for normal state.
|
||||||
|
*/
|
||||||
|
public int getColorNormal() {
|
||||||
|
return mColorNormal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColorNormalResId(@ColorRes int colorNormal) {
|
||||||
|
setColorNormal(getColor(colorNormal));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColorNormal(int color) {
|
||||||
|
if (mColorNormal != color) {
|
||||||
|
mColorNormal = color;
|
||||||
|
updateBackground();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current color for pressed state.
|
||||||
|
*/
|
||||||
|
public int getColorPressed() {
|
||||||
|
return mColorPressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColorPressedResId(@ColorRes int colorPressed) {
|
||||||
|
setColorPressed(getColor(colorPressed));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColorPressed(int color) {
|
||||||
|
if (mColorPressed != color) {
|
||||||
|
mColorPressed = color;
|
||||||
|
updateBackground();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current color for disabled state.
|
||||||
|
*/
|
||||||
|
public int getColorDisabled() {
|
||||||
|
return mColorDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColorDisabledResId(@ColorRes int colorDisabled) {
|
||||||
|
setColorDisabled(getColor(colorDisabled));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColorDisabled(int color) {
|
||||||
|
if (mColorDisabled != color) {
|
||||||
|
mColorDisabled = color;
|
||||||
|
updateBackground();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStrokeVisible(boolean visible) {
|
||||||
|
if (mStrokeVisible != visible) {
|
||||||
|
mStrokeVisible = visible;
|
||||||
|
updateBackground();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStrokeVisible() {
|
||||||
|
return mStrokeVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getColor(@ColorRes int id) {
|
||||||
|
return getResources().getColor(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
float getDimension(@DimenRes int id) {
|
||||||
|
return getResources().getDimension(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
mTitle = title;
|
||||||
|
TextView label = getLabelView();
|
||||||
|
if (label != null) {
|
||||||
|
label.setText(title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView getLabelView() {
|
||||||
|
return (TextView) getTag(R.id.fab_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return mTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
setMeasuredDimension(mDrawableSize, mDrawableSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateBackground() {
|
||||||
|
final float strokeWidth = getDimension(R.dimen.fab_stroke_width);
|
||||||
|
final float halfStrokeWidth = strokeWidth / 2f;
|
||||||
|
|
||||||
|
LayerDrawable layerDrawable = new LayerDrawable(
|
||||||
|
new Drawable[] {
|
||||||
|
getResources().getDrawable(mSize == SIZE_NORMAL ? R.drawable.fab_bg_normal : R.drawable.fab_bg_mini),
|
||||||
|
createFillDrawable(strokeWidth),
|
||||||
|
createOuterStrokeDrawable(strokeWidth),
|
||||||
|
getIconDrawable()
|
||||||
|
});
|
||||||
|
|
||||||
|
int iconOffset = (int) (mCircleSize - getDimension(R.dimen.fab_icon_size)) / 2;
|
||||||
|
|
||||||
|
int circleInsetHorizontal = (int) (mShadowRadius);
|
||||||
|
int circleInsetTop = (int) (mShadowRadius - mShadowOffset);
|
||||||
|
int circleInsetBottom = (int) (mShadowRadius + mShadowOffset);
|
||||||
|
|
||||||
|
layerDrawable.setLayerInset(1,
|
||||||
|
circleInsetHorizontal,
|
||||||
|
circleInsetTop,
|
||||||
|
circleInsetHorizontal,
|
||||||
|
circleInsetBottom);
|
||||||
|
|
||||||
|
layerDrawable.setLayerInset(2,
|
||||||
|
(int) (circleInsetHorizontal - halfStrokeWidth),
|
||||||
|
(int) (circleInsetTop - halfStrokeWidth),
|
||||||
|
(int) (circleInsetHorizontal - halfStrokeWidth),
|
||||||
|
(int) (circleInsetBottom - halfStrokeWidth));
|
||||||
|
|
||||||
|
layerDrawable.setLayerInset(3,
|
||||||
|
circleInsetHorizontal + iconOffset,
|
||||||
|
circleInsetTop + iconOffset,
|
||||||
|
circleInsetHorizontal + iconOffset,
|
||||||
|
circleInsetBottom + iconOffset);
|
||||||
|
|
||||||
|
setBackgroundCompat(layerDrawable);
|
||||||
|
}
|
||||||
|
|
||||||
|
Drawable getIconDrawable() {
|
||||||
|
if (mIconDrawable != null) {
|
||||||
|
return mIconDrawable;
|
||||||
|
} else if (mIcon != 0) {
|
||||||
|
return getResources().getDrawable(mIcon);
|
||||||
|
} else {
|
||||||
|
return new ColorDrawable(Color.TRANSPARENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private StateListDrawable createFillDrawable(float strokeWidth) {
|
||||||
|
StateListDrawable drawable = new StateListDrawable();
|
||||||
|
drawable.addState(new int[] { -android.R.attr.state_enabled }, createCircleDrawable(mColorDisabled, strokeWidth));
|
||||||
|
drawable.addState(new int[] { android.R.attr.state_pressed }, createCircleDrawable(mColorPressed, strokeWidth));
|
||||||
|
drawable.addState(new int[] { }, createCircleDrawable(mColorNormal, strokeWidth));
|
||||||
|
return drawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Drawable createCircleDrawable(int color, float strokeWidth) {
|
||||||
|
int alpha = Color.alpha(color);
|
||||||
|
int opaqueColor = opaque(color);
|
||||||
|
|
||||||
|
ShapeDrawable fillDrawable = new ShapeDrawable(new OvalShape());
|
||||||
|
|
||||||
|
final Paint paint = fillDrawable.getPaint();
|
||||||
|
paint.setAntiAlias(true);
|
||||||
|
paint.setColor(opaqueColor);
|
||||||
|
|
||||||
|
Drawable[] layers = {
|
||||||
|
fillDrawable,
|
||||||
|
createInnerStrokesDrawable(opaqueColor, strokeWidth)
|
||||||
|
};
|
||||||
|
|
||||||
|
LayerDrawable drawable = alpha == 255 || !mStrokeVisible
|
||||||
|
? new LayerDrawable(layers)
|
||||||
|
: new TranslucentLayerDrawable(alpha, layers);
|
||||||
|
|
||||||
|
int halfStrokeWidth = (int) (strokeWidth / 2f);
|
||||||
|
drawable.setLayerInset(1, halfStrokeWidth, halfStrokeWidth, halfStrokeWidth, halfStrokeWidth);
|
||||||
|
|
||||||
|
return drawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TranslucentLayerDrawable extends LayerDrawable {
|
||||||
|
private final int mAlpha;
|
||||||
|
|
||||||
|
public TranslucentLayerDrawable(int alpha, Drawable... layers) {
|
||||||
|
super(layers);
|
||||||
|
mAlpha = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(Canvas canvas) {
|
||||||
|
Rect bounds = getBounds();
|
||||||
|
canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, mAlpha, Canvas.ALL_SAVE_FLAG);
|
||||||
|
super.draw(canvas);
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Drawable createOuterStrokeDrawable(float strokeWidth) {
|
||||||
|
ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape());
|
||||||
|
|
||||||
|
final Paint paint = shapeDrawable.getPaint();
|
||||||
|
paint.setAntiAlias(true);
|
||||||
|
paint.setStrokeWidth(strokeWidth);
|
||||||
|
paint.setStyle(Style.STROKE);
|
||||||
|
paint.setColor(Color.BLACK);
|
||||||
|
paint.setAlpha(opacityToAlpha(0.02f));
|
||||||
|
|
||||||
|
return shapeDrawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int opacityToAlpha(float opacity) {
|
||||||
|
return (int) (255f * opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int darkenColor(int argb) {
|
||||||
|
return adjustColorBrightness(argb, 0.9f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int lightenColor(int argb) {
|
||||||
|
return adjustColorBrightness(argb, 1.1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int adjustColorBrightness(int argb, float factor) {
|
||||||
|
float[] hsv = new float[3];
|
||||||
|
Color.colorToHSV(argb, hsv);
|
||||||
|
|
||||||
|
hsv[2] = Math.min(hsv[2] * factor, 1f);
|
||||||
|
|
||||||
|
return Color.HSVToColor(Color.alpha(argb), hsv);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int halfTransparent(int argb) {
|
||||||
|
return Color.argb(
|
||||||
|
Color.alpha(argb) / 2,
|
||||||
|
Color.red(argb),
|
||||||
|
Color.green(argb),
|
||||||
|
Color.blue(argb)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int opaque(int argb) {
|
||||||
|
return Color.rgb(
|
||||||
|
Color.red(argb),
|
||||||
|
Color.green(argb),
|
||||||
|
Color.blue(argb)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Drawable createInnerStrokesDrawable(final int color, float strokeWidth) {
|
||||||
|
if (!mStrokeVisible) {
|
||||||
|
return new ColorDrawable(Color.TRANSPARENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape());
|
||||||
|
|
||||||
|
final int bottomStrokeColor = darkenColor(color);
|
||||||
|
final int bottomStrokeColorHalfTransparent = halfTransparent(bottomStrokeColor);
|
||||||
|
final int topStrokeColor = lightenColor(color);
|
||||||
|
final int topStrokeColorHalfTransparent = halfTransparent(topStrokeColor);
|
||||||
|
|
||||||
|
final Paint paint = shapeDrawable.getPaint();
|
||||||
|
paint.setAntiAlias(true);
|
||||||
|
paint.setStrokeWidth(strokeWidth);
|
||||||
|
paint.setStyle(Style.STROKE);
|
||||||
|
shapeDrawable.setShaderFactory(new ShaderFactory() {
|
||||||
|
@Override
|
||||||
|
public Shader resize(int width, int height) {
|
||||||
|
return new LinearGradient(width / 2, 0, width / 2, height,
|
||||||
|
new int[] { topStrokeColor, topStrokeColorHalfTransparent, color, bottomStrokeColorHalfTransparent, bottomStrokeColor },
|
||||||
|
new float[] { 0f, 0.2f, 0.5f, 0.8f, 1f },
|
||||||
|
TileMode.CLAMP
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return shapeDrawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
private void setBackgroundCompat(Drawable drawable) {
|
||||||
|
if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
|
||||||
|
setBackground(drawable);
|
||||||
|
} else {
|
||||||
|
setBackgroundDrawable(drawable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setVisibility(int visibility) {
|
||||||
|
TextView label = getLabelView();
|
||||||
|
if (label != null) {
|
||||||
|
label.setVisibility(visibility);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.setVisibility(visibility);
|
||||||
|
}
|
||||||
|
}
|
@ -60,6 +60,12 @@ import org.petero.droidfish.gamelogic.TimeControlData;
|
|||||||
import org.petero.droidfish.tb.Probe;
|
import org.petero.droidfish.tb.Probe;
|
||||||
import org.petero.droidfish.tb.ProbeResult;
|
import org.petero.droidfish.tb.ProbeResult;
|
||||||
|
|
||||||
|
import tourguide.tourguide.Overlay;
|
||||||
|
import tourguide.tourguide.Pointer;
|
||||||
|
import tourguide.tourguide.Sequence;
|
||||||
|
import tourguide.tourguide.ToolTip;
|
||||||
|
import tourguide.tourguide.TourGuide;
|
||||||
|
|
||||||
import com.kalab.chess.enginesupport.ChessEngine;
|
import com.kalab.chess.enginesupport.ChessEngine;
|
||||||
import com.kalab.chess.enginesupport.ChessEngineResolver;
|
import com.kalab.chess.enginesupport.ChessEngineResolver;
|
||||||
import com.larvalabs.svgandroid.SVG;
|
import com.larvalabs.svgandroid.SVG;
|
||||||
@ -191,7 +197,9 @@ public class DroidFish extends Activity
|
|||||||
private TextView status;
|
private TextView status;
|
||||||
private ScrollView moveListScroll;
|
private ScrollView moveListScroll;
|
||||||
private MoveListView moveList;
|
private MoveListView moveList;
|
||||||
|
private View thinkingScroll;
|
||||||
private TextView thinking;
|
private TextView thinking;
|
||||||
|
private View buttons;
|
||||||
private ImageButton custom1Button, custom2Button, custom3Button;
|
private ImageButton custom1Button, custom2Button, custom3Button;
|
||||||
private ImageButton modeButton, undoButton, redoButton;
|
private ImageButton modeButton, undoButton, redoButton;
|
||||||
private ButtonActions custom1ButtonActions, custom2ButtonActions, custom3ButtonActions;
|
private ButtonActions custom1ButtonActions, custom2ButtonActions, custom3ButtonActions;
|
||||||
@ -254,6 +262,9 @@ public class DroidFish extends Activity
|
|||||||
private Typeface figNotation;
|
private Typeface figNotation;
|
||||||
private Typeface defaultThinkingListTypeFace;
|
private Typeface defaultThinkingListTypeFace;
|
||||||
|
|
||||||
|
private boolean guideShowOnStart;
|
||||||
|
private TourGuide tourGuide;
|
||||||
|
|
||||||
|
|
||||||
/** Defines all configurable button actions. */
|
/** Defines all configurable button actions. */
|
||||||
private ActionFactory actionFactory = new ActionFactory() {
|
private ActionFactory actionFactory = new ActionFactory() {
|
||||||
@ -486,6 +497,94 @@ public class DroidFish extends Activity
|
|||||||
else
|
else
|
||||||
loadPGNFromFile(intentFilename);
|
loadPGNFromFile(intentFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startTourGuide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startTourGuide(){
|
||||||
|
if (!guideShowOnStart)
|
||||||
|
return;
|
||||||
|
|
||||||
|
tourGuide = TourGuide.init(this);
|
||||||
|
ArrayList<TourGuide> guides = new ArrayList<TourGuide>();
|
||||||
|
|
||||||
|
TourGuide tg = TourGuide.init(this);
|
||||||
|
tg.setToolTip(new ToolTip()
|
||||||
|
.setTitle(getString(R.string.tour_leftMenu_title))
|
||||||
|
.setDescription(getString(R.string.tour_leftMenu_desc))
|
||||||
|
.setGravity(Gravity.BOTTOM | Gravity.RIGHT));
|
||||||
|
tg.playLater(whiteTitleText);
|
||||||
|
guides.add(tg);
|
||||||
|
|
||||||
|
tg = TourGuide.init(this);
|
||||||
|
tg.setToolTip(new ToolTip()
|
||||||
|
.setTitle(getString(R.string.tour_rightMenu_title))
|
||||||
|
.setDescription(getString(R.string.tour_rightMenu_desc))
|
||||||
|
.setGravity(Gravity.BOTTOM | Gravity.LEFT));
|
||||||
|
tg.playLater(blackTitleText);
|
||||||
|
guides.add(tg);
|
||||||
|
|
||||||
|
tg = TourGuide.init(this);
|
||||||
|
int gravity = !landScapeView() ? Gravity.BOTTOM : leftHandedView() ? Gravity.LEFT : Gravity.RIGHT;
|
||||||
|
tg.setToolTip(new ToolTip()
|
||||||
|
.setTitle(getString(R.string.tour_chessBoard_title))
|
||||||
|
.setDescription(getString(R.string.tour_chessBoard_desc))
|
||||||
|
.setGravity(gravity));
|
||||||
|
tg.playLater(cb);
|
||||||
|
guides.add(tg);
|
||||||
|
|
||||||
|
tg = TourGuide.init(this);
|
||||||
|
gravity = !landScapeView() ? Gravity.TOP : Gravity.BOTTOM;
|
||||||
|
tg.setToolTip(new ToolTip()
|
||||||
|
.setTitle(getString(R.string.tour_buttons_title))
|
||||||
|
.setDescription(getString(R.string.tour_buttons_desc))
|
||||||
|
.setGravity(gravity));
|
||||||
|
tg.playLater(buttons);
|
||||||
|
guides.add(tg);
|
||||||
|
|
||||||
|
tg = TourGuide.init(this);
|
||||||
|
gravity = !landScapeView() ? Gravity.TOP : leftHandedView() ? Gravity.RIGHT : Gravity.LEFT;
|
||||||
|
tg.setToolTip(new ToolTip()
|
||||||
|
.setTitle(getString(R.string.tour_moveList_title))
|
||||||
|
.setDescription(getString(R.string.tour_moveList_desc))
|
||||||
|
.setGravity(gravity));
|
||||||
|
tg.playLater(moveListScroll);
|
||||||
|
guides.add(tg);
|
||||||
|
|
||||||
|
tg = TourGuide.init(this);
|
||||||
|
tg.setToolTip(new ToolTip()
|
||||||
|
.setTitle(getString(R.string.tour_analysis_title))
|
||||||
|
.setDescription(getString(R.string.tour_analysis_desc))
|
||||||
|
.setGravity(Gravity.TOP));
|
||||||
|
tg.playLater(thinkingScroll);
|
||||||
|
guides.add(tg);
|
||||||
|
|
||||||
|
tg.setOverlay(new Overlay()
|
||||||
|
.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
guideShowOnStart = false;
|
||||||
|
Editor editor = settings.edit();
|
||||||
|
editor.putBoolean("guideShowOnStart", false);
|
||||||
|
editor.commit();
|
||||||
|
tourGuide.next();
|
||||||
|
tourGuide = null;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
Sequence sequence = new Sequence.SequenceBuilder()
|
||||||
|
.add(guides.toArray(new TourGuide[guides.size()]))
|
||||||
|
.setDefaultOverlay(new Overlay()
|
||||||
|
.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
tourGuide.next();
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.setDefaultPointer(new Pointer())
|
||||||
|
.setContinueMethod(Sequence.ContinueMethod.OverlayListener)
|
||||||
|
.build();
|
||||||
|
tourGuide.playInSequence(sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unicode code points for chess pieces
|
// Unicode code points for chess pieces
|
||||||
@ -664,12 +763,20 @@ public class DroidFish extends Activity
|
|||||||
updateThinkingInfo();
|
updateThinkingInfo();
|
||||||
ctrl.updateRemainingTime();
|
ctrl.updateRemainingTime();
|
||||||
ctrl.updateMaterialDiffList();
|
ctrl.updateMaterialDiffList();
|
||||||
|
if (tourGuide != null) {
|
||||||
|
tourGuide.cleanUp();
|
||||||
|
tourGuide = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return true if the current orientation is landscape. */
|
||||||
|
private final boolean landScapeView() {
|
||||||
|
return getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
|
||||||
|
}
|
||||||
|
|
||||||
/** Return true if left-handed layout should be used. */
|
/** Return true if left-handed layout should be used. */
|
||||||
private final boolean leftHandedView() {
|
private final boolean leftHandedView() {
|
||||||
return settings.getBoolean("leftHanded", false) &&
|
return settings.getBoolean("leftHanded", false) && landScapeView();
|
||||||
(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Re-read preferences settings. */
|
/** Re-read preferences settings. */
|
||||||
@ -708,6 +815,7 @@ public class DroidFish extends Activity
|
|||||||
status = (TextView)findViewById(R.id.status);
|
status = (TextView)findViewById(R.id.status);
|
||||||
moveListScroll = (ScrollView)findViewById(R.id.scrollView);
|
moveListScroll = (ScrollView)findViewById(R.id.scrollView);
|
||||||
moveList = (MoveListView)findViewById(R.id.moveList);
|
moveList = (MoveListView)findViewById(R.id.moveList);
|
||||||
|
thinkingScroll = (View)findViewById(R.id.scrollViewBot);
|
||||||
thinking = (TextView)findViewById(R.id.thinking);
|
thinking = (TextView)findViewById(R.id.thinking);
|
||||||
defaultThinkingListTypeFace = thinking.getTypeface();
|
defaultThinkingListTypeFace = thinking.getTypeface();
|
||||||
status.setFocusable(false);
|
status.setFocusable(false);
|
||||||
@ -909,6 +1017,7 @@ public class DroidFish extends Activity
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
buttons = (View)findViewById(R.id.buttons);
|
||||||
custom1Button = (ImageButton)findViewById(R.id.custom1Button);
|
custom1Button = (ImageButton)findViewById(R.id.custom1Button);
|
||||||
custom1ButtonActions.setImageButton(custom1Button, this);
|
custom1ButtonActions.setImageButton(custom1Button, this);
|
||||||
custom2Button = (ImageButton)findViewById(R.id.custom2Button);
|
custom2Button = (ImageButton)findViewById(R.id.custom2Button);
|
||||||
@ -1078,6 +1187,8 @@ public class DroidFish extends Activity
|
|||||||
custom3ButtonActions.readPrefs(settings, actionFactory);
|
custom3ButtonActions.readPrefs(settings, actionFactory);
|
||||||
updateButtons();
|
updateButtons();
|
||||||
|
|
||||||
|
guideShowOnStart = settings.getBoolean("guideShowOnStart", true);
|
||||||
|
|
||||||
bookOptions.filename = settings.getString("bookFile", "");
|
bookOptions.filename = settings.getString("bookFile", "");
|
||||||
bookOptions.maxLength = getIntSetting("bookMaxLength", 1000000);
|
bookOptions.maxLength = getIntSetting("bookMaxLength", 1000000);
|
||||||
bookOptions.preferMainLines = settings.getBoolean("bookPreferMainLines", false);
|
bookOptions.preferMainLines = settings.getBoolean("bookPreferMainLines", false);
|
||||||
|
311
DroidFish/src/tourguide/tourguide/FrameLayoutWithHole.java
Normal file
311
DroidFish/src/tourguide/tourguide/FrameLayoutWithHole.java
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
package tourguide.tourguide;
|
||||||
|
|
||||||
|
import android.animation.AnimatorSet;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Point;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
|
import android.graphics.PorterDuffXfermode;
|
||||||
|
import android.support.v4.view.MotionEventCompat;
|
||||||
|
import android.text.TextPaint;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Display;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.animation.Animation;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: document your custom view class.
|
||||||
|
*/
|
||||||
|
public class FrameLayoutWithHole extends FrameLayout {
|
||||||
|
private TextPaint mTextPaint;
|
||||||
|
private Activity mActivity;
|
||||||
|
private TourGuide.MotionType mMotionType;
|
||||||
|
private Paint mEraser;
|
||||||
|
|
||||||
|
Bitmap mEraserBitmap;
|
||||||
|
private Canvas mEraserCanvas;
|
||||||
|
private Paint mPaint;
|
||||||
|
private Paint transparentPaint;
|
||||||
|
private View mViewHole; // This is the targeted view to be highlighted, where the hole should be placed
|
||||||
|
private int mRadius;
|
||||||
|
private int [] mPos;
|
||||||
|
private float mDensity;
|
||||||
|
private Overlay mOverlay;
|
||||||
|
|
||||||
|
private ArrayList<AnimatorSet> mAnimatorSetArrayList;
|
||||||
|
|
||||||
|
public void setViewHole(View viewHole) {
|
||||||
|
this.mViewHole = viewHole;
|
||||||
|
enforceMotionType();
|
||||||
|
}
|
||||||
|
public void addAnimatorSet(AnimatorSet animatorSet){
|
||||||
|
if (mAnimatorSetArrayList==null){
|
||||||
|
mAnimatorSetArrayList = new ArrayList<AnimatorSet>();
|
||||||
|
}
|
||||||
|
mAnimatorSetArrayList.add(animatorSet);
|
||||||
|
}
|
||||||
|
private void enforceMotionType(){
|
||||||
|
Log.d("tourguide", "enforceMotionType 1");
|
||||||
|
if (mViewHole!=null) {Log.d("tourguide","enforceMotionType 2");
|
||||||
|
if (mMotionType!=null && mMotionType == TourGuide.MotionType.ClickOnly) {
|
||||||
|
Log.d("tourguide","enforceMotionType 3");
|
||||||
|
Log.d("tourguide","only Clicking");
|
||||||
|
mViewHole.setOnTouchListener(new OnTouchListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View view, MotionEvent motionEvent) {
|
||||||
|
mViewHole.getParent().requestDisallowInterceptTouchEvent(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (mMotionType!=null && mMotionType == TourGuide.MotionType.SwipeOnly) {
|
||||||
|
Log.d("tourguide","enforceMotionType 4");
|
||||||
|
Log.d("tourguide","only Swiping");
|
||||||
|
mViewHole.setClickable(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameLayoutWithHole(Activity context, View view) {
|
||||||
|
this(context, view, TourGuide.MotionType.AllowAll);
|
||||||
|
}
|
||||||
|
public FrameLayoutWithHole(Activity context, View view, TourGuide.MotionType motionType) {
|
||||||
|
this(context, view, motionType, new Overlay());
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameLayoutWithHole(Activity context, View view, TourGuide.MotionType motionType, Overlay overlay) {
|
||||||
|
super(context);
|
||||||
|
mActivity = context;
|
||||||
|
mViewHole = view;
|
||||||
|
init(null, 0);
|
||||||
|
enforceMotionType();
|
||||||
|
mOverlay = overlay;
|
||||||
|
|
||||||
|
int [] pos = new int[2];
|
||||||
|
mViewHole.getLocationOnScreen(pos);
|
||||||
|
mPos = pos;
|
||||||
|
|
||||||
|
mDensity = context.getResources().getDisplayMetrics().density;
|
||||||
|
int padding = (int)(20 * mDensity);
|
||||||
|
|
||||||
|
if (mViewHole.getHeight() > mViewHole.getWidth()) {
|
||||||
|
mRadius = mViewHole.getHeight()/2 + padding;
|
||||||
|
} else {
|
||||||
|
mRadius = mViewHole.getWidth()/2 + padding;
|
||||||
|
}
|
||||||
|
mMotionType = motionType;
|
||||||
|
}
|
||||||
|
private void init(AttributeSet attrs, int defStyle) {
|
||||||
|
// Load attributes
|
||||||
|
// final TypedArray a = getContext().obtainStyledAttributes(
|
||||||
|
// attrs, FrameLayoutWithHole, defStyle, 0);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// a.recycle();
|
||||||
|
setWillNotDraw(false);
|
||||||
|
// Set up a default TextPaint object
|
||||||
|
mTextPaint = new TextPaint();
|
||||||
|
mTextPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
mTextPaint.setTextAlign(Paint.Align.LEFT);
|
||||||
|
|
||||||
|
Point size = new Point();
|
||||||
|
size.x = mActivity.getResources().getDisplayMetrics().widthPixels;
|
||||||
|
size.y = mActivity.getResources().getDisplayMetrics().heightPixels;
|
||||||
|
|
||||||
|
mEraserBitmap = Bitmap.createBitmap(size.x, size.y, Bitmap.Config.ARGB_8888);
|
||||||
|
mEraserCanvas = new Canvas(mEraserBitmap);
|
||||||
|
|
||||||
|
mPaint = new Paint();
|
||||||
|
mPaint.setColor(0xcc000000);
|
||||||
|
transparentPaint = new Paint();
|
||||||
|
transparentPaint.setColor(getResources().getColor(android.R.color.transparent));
|
||||||
|
transparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
|
||||||
|
|
||||||
|
mEraser = new Paint();
|
||||||
|
mEraser.setColor(0xFFFFFFFF);
|
||||||
|
mEraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
|
||||||
|
mEraser.setFlags(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
|
||||||
|
Log.d("tourguide","getHeight: "+ size.y);
|
||||||
|
Log.d("tourguide","getWidth: " + size.x);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean mCleanUpLock = false;
|
||||||
|
protected void cleanUp(){
|
||||||
|
if (getParent() != null) {
|
||||||
|
if (mOverlay!=null && mOverlay.mExitAnimation!=null) {
|
||||||
|
performOverlayExitAnimation();
|
||||||
|
} else {
|
||||||
|
((ViewGroup) this.getParent()).removeView(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void performOverlayExitAnimation(){
|
||||||
|
if (!mCleanUpLock) {
|
||||||
|
final FrameLayout _pointerToFrameLayout = this;
|
||||||
|
mCleanUpLock = true;
|
||||||
|
Log.d("tourguide","Overlay exit animation listener is overwritten...");
|
||||||
|
mOverlay.mExitAnimation.setAnimationListener(new Animation.AnimationListener() {
|
||||||
|
@Override public void onAnimationStart(Animation animation) {}
|
||||||
|
@Override public void onAnimationRepeat(Animation animation) {}
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animation animation) {
|
||||||
|
((ViewGroup) _pointerToFrameLayout.getParent()).removeView(_pointerToFrameLayout);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.startAnimation(mOverlay.mExitAnimation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* comment this whole method to cause a memory leak */
|
||||||
|
@Override
|
||||||
|
protected void onDetachedFromWindow() {
|
||||||
|
super.onDetachedFromWindow();
|
||||||
|
/* cleanup reference to prevent memory leak */
|
||||||
|
mEraserCanvas.setBitmap(null);
|
||||||
|
mEraserBitmap = null;
|
||||||
|
|
||||||
|
if (mAnimatorSetArrayList != null && mAnimatorSetArrayList.size() > 0){
|
||||||
|
for(int i=0;i<mAnimatorSetArrayList.size();i++){
|
||||||
|
mAnimatorSetArrayList.get(i).end();
|
||||||
|
mAnimatorSetArrayList.get(i).removeAllListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Show an event in the LogCat view, for debugging */
|
||||||
|
private void dumpEvent(MotionEvent event) {
|
||||||
|
String names[] = { "DOWN" , "UP" , "MOVE" , "CANCEL" , "OUTSIDE" ,
|
||||||
|
"POINTER_DOWN" , "POINTER_UP" , "7?" , "8?" , "9?" };
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int action = event.getAction();
|
||||||
|
int actionCode = action & MotionEvent.ACTION_MASK;
|
||||||
|
sb.append("event ACTION_" ).append(names[actionCode]);
|
||||||
|
if (actionCode == MotionEvent.ACTION_POINTER_DOWN
|
||||||
|
|| actionCode == MotionEvent.ACTION_POINTER_UP) {
|
||||||
|
sb.append("(pid " ).append(
|
||||||
|
action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
|
||||||
|
sb.append(")" );
|
||||||
|
}
|
||||||
|
sb.append("[" );
|
||||||
|
for (int i = 0; i < event.getPointerCount(); i++) {
|
||||||
|
sb.append("#" ).append(i);
|
||||||
|
sb.append("(pid " ).append(event.getPointerId(i));
|
||||||
|
sb.append(")=" ).append((int) event.getX(i));
|
||||||
|
sb.append("," ).append((int) event.getY(i));
|
||||||
|
if (i + 1 < event.getPointerCount())
|
||||||
|
sb.append(";" );
|
||||||
|
}
|
||||||
|
sb.append("]" );
|
||||||
|
Log.d("tourguide", sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||||
|
//first check if the location button should handle the touch event
|
||||||
|
dumpEvent(ev);
|
||||||
|
int action = MotionEventCompat.getActionMasked(ev);
|
||||||
|
if(mViewHole != null) {
|
||||||
|
int[] pos = new int[2];
|
||||||
|
mViewHole.getLocationOnScreen(pos);
|
||||||
|
Log.d("tourguide", "[dispatchTouchEvent] mViewHole.getHeight(): "+mViewHole.getHeight());
|
||||||
|
Log.d("tourguide", "[dispatchTouchEvent] mViewHole.getWidth(): "+mViewHole.getWidth());
|
||||||
|
|
||||||
|
Log.d("tourguide", "[dispatchTouchEvent] Touch X(): "+ev.getRawX());
|
||||||
|
Log.d("tourguide", "[dispatchTouchEvent] Touch Y(): "+ev.getRawY());
|
||||||
|
|
||||||
|
// Log.d("tourguide", "[dispatchTouchEvent] X of image: "+pos[0]);
|
||||||
|
// Log.d("tourguide", "[dispatchTouchEvent] Y of image: "+pos[1]);
|
||||||
|
|
||||||
|
Log.d("tourguide", "[dispatchTouchEvent] X lower bound: "+ pos[0]);
|
||||||
|
Log.d("tourguide", "[dispatchTouchEvent] X higher bound: "+(pos[0] +mViewHole.getWidth()));
|
||||||
|
|
||||||
|
Log.d("tourguide", "[dispatchTouchEvent] Y lower bound: "+ pos[1]);
|
||||||
|
Log.d("tourguide", "[dispatchTouchEvent] Y higher bound: "+(pos[1] +mViewHole.getHeight()));
|
||||||
|
|
||||||
|
if(ev.getRawY() >= pos[1] && ev.getRawY() <= (pos[1] + mViewHole.getHeight()) && ev.getRawX() >= pos[0] && ev.getRawX() <= (pos[0] + mViewHole.getWidth())) { //location button event
|
||||||
|
Log.d("tourguide","to the BOTTOM!");
|
||||||
|
Log.d("tourguide",""+ev.getAction());
|
||||||
|
|
||||||
|
// switch(action) {
|
||||||
|
// case (MotionEvent.ACTION_DOWN) :
|
||||||
|
// Log.d("tourguide","Action was DOWN");
|
||||||
|
// return false;
|
||||||
|
// case (MotionEvent.ACTION_MOVE) :
|
||||||
|
// Log.d("tourguide","Action was MOVE");
|
||||||
|
// return true;
|
||||||
|
// case (MotionEvent.ACTION_UP) :
|
||||||
|
// Log.d("tourguide","Action was UP");
|
||||||
|
//// ev.setAction(MotionEvent.ACTION_DOWN|MotionEvent.ACTION_UP);
|
||||||
|
//// return super.dispatchTouchEvent(ev);
|
||||||
|
// return false;
|
||||||
|
// case (MotionEvent.ACTION_CANCEL) :
|
||||||
|
// Log.d("tourguide","Action was CANCEL");
|
||||||
|
// return true;
|
||||||
|
// case (MotionEvent.ACTION_OUTSIDE) :
|
||||||
|
// Log.d("tourguide","Movement occurred outside bounds " +
|
||||||
|
// "of current screen element");
|
||||||
|
// return true;
|
||||||
|
// default :
|
||||||
|
// return super.dispatchTouchEvent(ev);
|
||||||
|
// }
|
||||||
|
// return mViewHole.onTouchEvent(ev);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.dispatchTouchEvent(ev);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
super.onDraw(canvas);
|
||||||
|
mEraserBitmap.eraseColor(Color.TRANSPARENT);
|
||||||
|
|
||||||
|
if (mOverlay!=null) {
|
||||||
|
mEraserCanvas.drawColor(mOverlay.mBackgroundColor);
|
||||||
|
int padding = (int) (10 * mDensity);
|
||||||
|
if (mOverlay.mStyle == Overlay.Style.Rectangle) {
|
||||||
|
mEraserCanvas.drawRect(mPos[0] - padding, mPos[1] - padding, mPos[0] + mViewHole.getWidth() + padding, mPos[1] + mViewHole.getHeight() + padding, mEraser);
|
||||||
|
} else {
|
||||||
|
mEraserCanvas.drawCircle(mPos[0] + mViewHole.getWidth() / 2, mPos[1] + mViewHole.getHeight() / 2, mRadius, mEraser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
canvas.drawBitmap(mEraserBitmap, 0, 0, null);
|
||||||
|
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void onAttachedToWindow() {
|
||||||
|
super.onAttachedToWindow();
|
||||||
|
if (mOverlay!=null && mOverlay.mEnterAnimation!=null) {
|
||||||
|
this.startAnimation(mOverlay.mEnterAnimation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Convenient method to obtain screen width in pixel
|
||||||
|
*
|
||||||
|
* @param activity
|
||||||
|
* @return screen width in pixel
|
||||||
|
*/
|
||||||
|
public int getScreenWidth(Activity activity){
|
||||||
|
return activity.getResources().getDisplayMetrics().widthPixels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Convenient method to obtain screen height in pixel
|
||||||
|
*
|
||||||
|
* @param activity
|
||||||
|
* @return screen width in pixel
|
||||||
|
*/
|
||||||
|
public int getScreenHeight(Activity activity){
|
||||||
|
return activity.getResources().getDisplayMetrics().heightPixels;
|
||||||
|
}
|
||||||
|
}
|
83
DroidFish/src/tourguide/tourguide/Overlay.java
Normal file
83
DroidFish/src/tourguide/tourguide/Overlay.java
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package tourguide.tourguide;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.animation.Animation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tanjunrong on 6/20/15.
|
||||||
|
*/
|
||||||
|
public class Overlay {
|
||||||
|
public int mBackgroundColor;
|
||||||
|
public boolean mDisableClick;
|
||||||
|
public Style mStyle;
|
||||||
|
public Animation mEnterAnimation, mExitAnimation;
|
||||||
|
public View.OnClickListener mOnClickListener;
|
||||||
|
|
||||||
|
public enum Style {
|
||||||
|
Circle, Rectangle
|
||||||
|
}
|
||||||
|
public Overlay() {
|
||||||
|
this(true, Color.parseColor("#55000000"), Style.Circle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Overlay(boolean disableClick, int backgroundColor, Style style) {
|
||||||
|
mDisableClick = disableClick;
|
||||||
|
mBackgroundColor = backgroundColor;
|
||||||
|
mStyle = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set background color
|
||||||
|
* @param backgroundColor
|
||||||
|
* @return return ToolTip instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public Overlay setBackgroundColor(int backgroundColor){
|
||||||
|
mBackgroundColor = backgroundColor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to true if you want to block all user input to pass through this overlay, set to false if you want to allow user input under the overlay
|
||||||
|
* @param yes_no
|
||||||
|
* @return return Overlay instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public Overlay disableClick(boolean yes_no){
|
||||||
|
mDisableClick = yes_no;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Overlay setStyle(Style style){
|
||||||
|
mStyle = style;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set enter animation
|
||||||
|
* @param enterAnimation
|
||||||
|
* @return return Overlay instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public Overlay setEnterAnimation(Animation enterAnimation){
|
||||||
|
mEnterAnimation = enterAnimation;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set exit animation
|
||||||
|
* @param exitAnimation
|
||||||
|
* @return return Overlay instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public Overlay setExitAnimation(Animation exitAnimation){
|
||||||
|
mExitAnimation = exitAnimation;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set onClickListener for the Overlay
|
||||||
|
* @param onClickListener
|
||||||
|
* @return return Overlay instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public Overlay setOnClickListener(View.OnClickListener onClickListener){
|
||||||
|
mOnClickListener=onClickListener;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
41
DroidFish/src/tourguide/tourguide/Pointer.java
Normal file
41
DroidFish/src/tourguide/tourguide/Pointer.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package tourguide.tourguide;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.view.Gravity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tanjunrong on 6/20/15.
|
||||||
|
*/
|
||||||
|
public class Pointer {
|
||||||
|
public int mGravity = Gravity.CENTER;
|
||||||
|
public int mColor = Color.WHITE;
|
||||||
|
|
||||||
|
public Pointer() {
|
||||||
|
this(Gravity.CENTER, Color.parseColor("#FFFFFF"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pointer(int gravity, int color) {
|
||||||
|
this.mGravity = gravity;
|
||||||
|
this.mColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set color
|
||||||
|
* @param color
|
||||||
|
* @return return Pointer instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public Pointer setColor(int color){
|
||||||
|
mColor = color;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set gravity
|
||||||
|
* @param gravity
|
||||||
|
* @return return Pointer instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public Pointer setGravity(int gravity){
|
||||||
|
mGravity = gravity;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
219
DroidFish/src/tourguide/tourguide/Sequence.java
Normal file
219
DroidFish/src/tourguide/tourguide/Sequence.java
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
package tourguide.tourguide;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by aaronliew on 8/7/15.
|
||||||
|
*/
|
||||||
|
public class Sequence {
|
||||||
|
TourGuide [] mTourGuideArray;
|
||||||
|
Overlay mDefaultOverlay;
|
||||||
|
ToolTip mDefaultToolTip;
|
||||||
|
Pointer mDefaultPointer;
|
||||||
|
|
||||||
|
ContinueMethod mContinueMethod;
|
||||||
|
boolean mDisableTargetButton;
|
||||||
|
public int mCurrentSequence;
|
||||||
|
TourGuide mParentTourGuide;
|
||||||
|
public enum ContinueMethod {
|
||||||
|
Overlay, OverlayListener
|
||||||
|
}
|
||||||
|
private Sequence(SequenceBuilder builder){
|
||||||
|
this.mTourGuideArray = builder.mTourGuideArray;
|
||||||
|
this.mDefaultOverlay = builder.mDefaultOverlay;
|
||||||
|
this.mDefaultToolTip = builder.mDefaultToolTip;
|
||||||
|
this.mDefaultPointer = builder.mDefaultPointer;
|
||||||
|
this.mContinueMethod = builder.mContinueMethod;
|
||||||
|
this.mCurrentSequence = builder.mCurrentSequence;
|
||||||
|
|
||||||
|
// TODO: to be implemented
|
||||||
|
this.mDisableTargetButton = builder.mDisableTargetButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the parent TourGuide that will run this Sequence
|
||||||
|
*/
|
||||||
|
protected void setParentTourGuide(TourGuide parentTourGuide){
|
||||||
|
mParentTourGuide = parentTourGuide;
|
||||||
|
|
||||||
|
if(mContinueMethod == ContinueMethod.Overlay) {
|
||||||
|
for (final TourGuide tourGuide : mTourGuideArray) {
|
||||||
|
tourGuide.mOverlay.mOnClickListener = new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
mParentTourGuide.next();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TourGuide getNextTourGuide() {
|
||||||
|
return mTourGuideArray[mCurrentSequence];
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContinueMethod getContinueMethod() {
|
||||||
|
return mContinueMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TourGuide[] getTourGuideArray() {
|
||||||
|
return mTourGuideArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Overlay getDefaultOverlay() {
|
||||||
|
return mDefaultOverlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ToolTip getDefaultToolTip() {
|
||||||
|
return mDefaultToolTip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ToolTip getToolTip() {
|
||||||
|
// individual tour guide has higher priority
|
||||||
|
if (mTourGuideArray[mCurrentSequence].mToolTip != null){
|
||||||
|
return mTourGuideArray[mCurrentSequence].mToolTip;
|
||||||
|
} else {
|
||||||
|
return mDefaultToolTip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Overlay getOverlay() {
|
||||||
|
// Overlay is used as a method to proceed to next TourGuide, so the default overlay is already assigned appropriately if needed
|
||||||
|
return mTourGuideArray[mCurrentSequence].mOverlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pointer getPointer() {
|
||||||
|
// individual tour guide has higher priority
|
||||||
|
if (mTourGuideArray[mCurrentSequence].mPointer != null){
|
||||||
|
return mTourGuideArray[mCurrentSequence].mPointer;
|
||||||
|
} else {
|
||||||
|
return mDefaultPointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SequenceBuilder {
|
||||||
|
TourGuide [] mTourGuideArray;
|
||||||
|
Overlay mDefaultOverlay;
|
||||||
|
ToolTip mDefaultToolTip;
|
||||||
|
Pointer mDefaultPointer;
|
||||||
|
ContinueMethod mContinueMethod;
|
||||||
|
int mCurrentSequence;
|
||||||
|
boolean mDisableTargetButton;
|
||||||
|
|
||||||
|
public SequenceBuilder add(TourGuide... tourGuideArray){
|
||||||
|
mTourGuideArray = tourGuideArray;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SequenceBuilder setDefaultOverlay(Overlay defaultOverlay){
|
||||||
|
mDefaultOverlay = defaultOverlay;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This might not be useful, but who knows.. maybe someone needs it
|
||||||
|
public SequenceBuilder setDefaultToolTip(ToolTip defaultToolTip){
|
||||||
|
mDefaultToolTip = defaultToolTip;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SequenceBuilder setDefaultPointer(Pointer defaultPointer){
|
||||||
|
mDefaultPointer = defaultPointer;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this is an uncompleted feature, make it private first
|
||||||
|
// This is intended to be used to disable the button, so people cannot click on in during a Tour, instead, people can only click on Next button or Overlay to proceed
|
||||||
|
private SequenceBuilder setDisableButton(boolean disableTargetButton){
|
||||||
|
mDisableTargetButton = disableTargetButton;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param continueMethod ContinueMethod.Overlay or ContinueMethod.OverlayListener
|
||||||
|
* ContnueMethod.Overlay - clicking on Overlay will make TourGuide proceed to the next one.
|
||||||
|
* ContinueMethod.OverlayListener - you need to provide OverlayListeners, and call tourGuideHandler.next() in the listener to proceed to the next one.
|
||||||
|
*/
|
||||||
|
public SequenceBuilder setContinueMethod(ContinueMethod continueMethod){
|
||||||
|
mContinueMethod = continueMethod;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sequence build(){
|
||||||
|
mCurrentSequence = 0;
|
||||||
|
checkIfContinueMethodNull();
|
||||||
|
checkAtLeastTwoTourGuideSupplied();
|
||||||
|
checkOverlayListener(mContinueMethod);
|
||||||
|
|
||||||
|
return new Sequence(this);
|
||||||
|
}
|
||||||
|
private void checkIfContinueMethodNull(){
|
||||||
|
if (mContinueMethod == null){
|
||||||
|
throw new IllegalArgumentException("Continue Method is not set. Please provide ContinueMethod in setContinueMethod");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void checkAtLeastTwoTourGuideSupplied() {
|
||||||
|
if (mTourGuideArray == null || mTourGuideArray.length <= 1){
|
||||||
|
throw new IllegalArgumentException("In order to run a sequence, you must at least supply 2 TourGuide into Sequence using add()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void checkOverlayListener(ContinueMethod continueMethod) {
|
||||||
|
if(continueMethod == ContinueMethod.OverlayListener){
|
||||||
|
boolean pass = true;
|
||||||
|
if (mDefaultOverlay != null && mDefaultOverlay.mOnClickListener != null) {
|
||||||
|
pass = true;
|
||||||
|
// when default listener is available, we loop through individual tour guide, and
|
||||||
|
// assign default listener to individual tour guide
|
||||||
|
for (TourGuide tourGuide : mTourGuideArray) {
|
||||||
|
if (tourGuide.mOverlay == null) {
|
||||||
|
tourGuide.mOverlay = mDefaultOverlay;
|
||||||
|
}
|
||||||
|
if (tourGuide.mOverlay != null && tourGuide.mOverlay.mOnClickListener == null) {
|
||||||
|
tourGuide.mOverlay.mOnClickListener = mDefaultOverlay.mOnClickListener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // case where: default listener is not available
|
||||||
|
|
||||||
|
for (TourGuide tourGuide : mTourGuideArray) {
|
||||||
|
//Both of the overlay and default listener is not null, throw the error
|
||||||
|
if (tourGuide.mOverlay != null && tourGuide.mOverlay.mOnClickListener == null) {
|
||||||
|
pass = false;
|
||||||
|
break;
|
||||||
|
} else if (tourGuide.mOverlay == null){
|
||||||
|
pass = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pass){
|
||||||
|
throw new IllegalArgumentException("ContinueMethod.OverlayListener is chosen as the ContinueMethod, but no Default Overlay Listener is set, or not all Overlay.mListener is set for all the TourGuide passed in.");
|
||||||
|
}
|
||||||
|
} else if(continueMethod == ContinueMethod.Overlay){
|
||||||
|
// when Overlay ContinueMethod is used, listener must not be supplied (to avoid unexpected result)
|
||||||
|
boolean pass = true;
|
||||||
|
if (mDefaultOverlay != null && mDefaultOverlay.mOnClickListener != null) {
|
||||||
|
pass = false;
|
||||||
|
} else {
|
||||||
|
for (TourGuide tourGuide : mTourGuideArray) {
|
||||||
|
if (tourGuide.mOverlay != null && tourGuide.mOverlay.mOnClickListener != null ) {
|
||||||
|
pass = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mDefaultOverlay != null) {
|
||||||
|
for (TourGuide tourGuide : mTourGuideArray) {
|
||||||
|
if (tourGuide.mOverlay == null) {
|
||||||
|
tourGuide.mOverlay = mDefaultOverlay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pass) {
|
||||||
|
throw new IllegalArgumentException("ContinueMethod.Overlay is chosen as the ContinueMethod, but either default overlay listener is still set OR individual overlay listener is still set, make sure to clear all Overlay listener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
119
DroidFish/src/tourguide/tourguide/ToolTip.java
Normal file
119
DroidFish/src/tourguide/tourguide/ToolTip.java
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
package tourguide.tourguide;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.animation.AlphaAnimation;
|
||||||
|
import android.view.animation.Animation;
|
||||||
|
import android.view.animation.BounceInterpolator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tanjunrong on 6/17/15.
|
||||||
|
*/
|
||||||
|
public class ToolTip {
|
||||||
|
public String mTitle, mDescription;
|
||||||
|
public int mBackgroundColor, mTextColor;
|
||||||
|
public Animation mEnterAnimation, mExitAnimation;
|
||||||
|
public boolean mShadow;
|
||||||
|
public int mGravity;
|
||||||
|
public View.OnClickListener mOnClickListener;
|
||||||
|
|
||||||
|
public ToolTip(){
|
||||||
|
/* default values */
|
||||||
|
mTitle = "";
|
||||||
|
mDescription = "";
|
||||||
|
mBackgroundColor = Color.parseColor("#3498db");
|
||||||
|
mTextColor = Color.parseColor("#FFFFFF");
|
||||||
|
|
||||||
|
mEnterAnimation = new AlphaAnimation(0f, 1f);
|
||||||
|
mEnterAnimation.setDuration(1000);
|
||||||
|
mEnterAnimation.setFillAfter(true);
|
||||||
|
mEnterAnimation.setInterpolator(new BounceInterpolator());
|
||||||
|
mShadow = true;
|
||||||
|
|
||||||
|
// TODO: exit animation
|
||||||
|
mGravity = Gravity.CENTER;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set title text
|
||||||
|
* @param title
|
||||||
|
* @return return ToolTip instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public ToolTip setTitle(String title){
|
||||||
|
mTitle = title;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set description text
|
||||||
|
* @param description
|
||||||
|
* @return return ToolTip instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public ToolTip setDescription(String description){
|
||||||
|
mDescription = description;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set background color
|
||||||
|
* @param backgroundColor
|
||||||
|
* @return return ToolTip instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public ToolTip setBackgroundColor(int backgroundColor){
|
||||||
|
mBackgroundColor = backgroundColor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set text color
|
||||||
|
* @param textColor
|
||||||
|
* @return return ToolTip instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public ToolTip setTextColor(int textColor){
|
||||||
|
mTextColor = textColor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set enter animation
|
||||||
|
* @param enterAnimation
|
||||||
|
* @return return ToolTip instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public ToolTip setEnterAnimation(Animation enterAnimation){
|
||||||
|
mEnterAnimation = enterAnimation;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set exit animation
|
||||||
|
* @param exitAnimation
|
||||||
|
* @return return ToolTip instance for chaining purpose
|
||||||
|
*/
|
||||||
|
// TODO:
|
||||||
|
// public ToolTip setExitAnimation(Animation exitAnimation){
|
||||||
|
// mExitAnimation = exitAnimation;
|
||||||
|
// return this;
|
||||||
|
// }
|
||||||
|
/**
|
||||||
|
* Set the gravity, the setGravity is centered relative to the targeted button
|
||||||
|
* @param gravity Gravity.CENTER, Gravity.TOP, Gravity.BOTTOM, etc
|
||||||
|
* @return return ToolTip instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public ToolTip setGravity(int gravity){
|
||||||
|
mGravity = gravity;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set if you want to have setShadow
|
||||||
|
* @param shadow
|
||||||
|
* @return return ToolTip instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public ToolTip setShadow(boolean shadow){
|
||||||
|
mShadow = shadow;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ToolTip setOnClickListener(View.OnClickListener onClickListener){
|
||||||
|
mOnClickListener = onClickListener;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
633
DroidFish/src/tourguide/tourguide/TourGuide.java
Normal file
633
DroidFish/src/tourguide/tourguide/TourGuide.java
Normal file
@ -0,0 +1,633 @@
|
|||||||
|
package tourguide.tourguide;
|
||||||
|
|
||||||
|
import org.petero.droidfish.R;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorSet;
|
||||||
|
import android.animation.ObjectAnimator;
|
||||||
|
import android.animation.ValueAnimator;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Point;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Display;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewTreeObserver;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import net.i2p.android.ext.floatingactionbutton.FloatingActionButton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tanjunrong on 2/10/15.
|
||||||
|
*/
|
||||||
|
public class TourGuide {
|
||||||
|
/**
|
||||||
|
* This describes the animation techniques
|
||||||
|
* */
|
||||||
|
public enum Technique {
|
||||||
|
Click, HorizontalLeft, HorizontalRight, VerticalUpward, VerticalDownward
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This describes the allowable motion, for example if you want the users to learn about clicking, but want to stop them from swiping, then use ClickOnly
|
||||||
|
*/
|
||||||
|
public enum MotionType {
|
||||||
|
AllowAll, ClickOnly, SwipeOnly
|
||||||
|
}
|
||||||
|
private Technique mTechnique;
|
||||||
|
private View mHighlightedView;
|
||||||
|
private Activity mActivity;
|
||||||
|
private MotionType mMotionType;
|
||||||
|
private FrameLayoutWithHole mFrameLayout;
|
||||||
|
private View mToolTipViewGroup;
|
||||||
|
public ToolTip mToolTip;
|
||||||
|
public Pointer mPointer;
|
||||||
|
public Overlay mOverlay;
|
||||||
|
|
||||||
|
private Sequence mSequence;
|
||||||
|
|
||||||
|
/*************
|
||||||
|
*
|
||||||
|
* Public API
|
||||||
|
*
|
||||||
|
*************/
|
||||||
|
|
||||||
|
/* Static builder */
|
||||||
|
public static TourGuide init(Activity activity){
|
||||||
|
return new TourGuide(activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Constructor */
|
||||||
|
public TourGuide(Activity activity){
|
||||||
|
mActivity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter for the animation to be used
|
||||||
|
* @param technique Animation to be used
|
||||||
|
* @return return TourGuide instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public TourGuide with(Technique technique) {
|
||||||
|
mTechnique = technique;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets which motion type is motionType
|
||||||
|
* @param motionType
|
||||||
|
* @return return TourGuide instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public TourGuide motionType(MotionType motionType){
|
||||||
|
mMotionType = motionType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the duration
|
||||||
|
* @param view the view in which the tutorial button will be placed on top of
|
||||||
|
* @return return TourGuide instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public TourGuide playOn(View view){
|
||||||
|
mHighlightedView = view;
|
||||||
|
setupView();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the overlay
|
||||||
|
* @param overlay this overlay object should contain the attributes of the overlay, such as background color, animation, Style, etc
|
||||||
|
* @return return TourGuide instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public TourGuide setOverlay(Overlay overlay){
|
||||||
|
mOverlay = overlay;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set the toolTip
|
||||||
|
* @param toolTip this toolTip object should contain the attributes of the ToolTip, such as, the title text, and the description text, background color, etc
|
||||||
|
* @return return TourGuide instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public TourGuide setToolTip(ToolTip toolTip){
|
||||||
|
mToolTip = toolTip;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set the Pointer
|
||||||
|
* @param pointer this pointer object should contain the attributes of the Pointer, such as the pointer color, pointer gravity, etc, refer to @Link{pointer}
|
||||||
|
* @return return TourGuide instance for chaining purpose
|
||||||
|
*/
|
||||||
|
public TourGuide setPointer(Pointer pointer){
|
||||||
|
mPointer = pointer;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Clean up the tutorial that is added to the activity
|
||||||
|
*/
|
||||||
|
public void cleanUp(){
|
||||||
|
mFrameLayout.cleanUp();
|
||||||
|
if (mToolTipViewGroup!=null) {
|
||||||
|
((ViewGroup) mActivity.getWindow().getDecorView()).removeView(mToolTipViewGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TourGuide playLater(View view){
|
||||||
|
mHighlightedView = view;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************
|
||||||
|
* Sequence related method
|
||||||
|
**************************/
|
||||||
|
|
||||||
|
public TourGuide playInSequence(Sequence sequence){
|
||||||
|
setSequence(sequence);
|
||||||
|
next();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TourGuide setSequence(Sequence sequence){
|
||||||
|
mSequence = sequence;
|
||||||
|
mSequence.setParentTourGuide(this);
|
||||||
|
for (TourGuide tourGuide : sequence.mTourGuideArray){
|
||||||
|
if (tourGuide.mHighlightedView == null) {
|
||||||
|
throw new NullPointerException("Please specify the view using 'playLater' method");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TourGuide next(){
|
||||||
|
if (mFrameLayout!=null) {
|
||||||
|
cleanUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSequence.mCurrentSequence < mSequence.mTourGuideArray.length) {
|
||||||
|
setToolTip(mSequence.getToolTip());
|
||||||
|
setPointer(mSequence.getPointer());
|
||||||
|
setOverlay(mSequence.getOverlay());
|
||||||
|
|
||||||
|
mHighlightedView = mSequence.getNextTourGuide().mHighlightedView;
|
||||||
|
|
||||||
|
setupView();
|
||||||
|
mSequence.mCurrentSequence++;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return FrameLayoutWithHole that is used as overlay
|
||||||
|
*/
|
||||||
|
public FrameLayoutWithHole getOverlay(){
|
||||||
|
return mFrameLayout;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the ToolTip container View
|
||||||
|
*/
|
||||||
|
public View getToolTip(){
|
||||||
|
return mToolTipViewGroup;
|
||||||
|
}
|
||||||
|
/******
|
||||||
|
*
|
||||||
|
* Private methods
|
||||||
|
*
|
||||||
|
*******/
|
||||||
|
//TODO: move into Pointer
|
||||||
|
private int getXBasedOnGravity(int width){
|
||||||
|
int [] pos = new int[2];
|
||||||
|
mHighlightedView.getLocationOnScreen(pos);
|
||||||
|
int x = pos[0];
|
||||||
|
if((mPointer.mGravity & Gravity.RIGHT) == Gravity.RIGHT){
|
||||||
|
return x+mHighlightedView.getWidth()-width;
|
||||||
|
} else if ((mPointer.mGravity & Gravity.LEFT) == Gravity.LEFT) {
|
||||||
|
return x;
|
||||||
|
} else { // this is center
|
||||||
|
return x+mHighlightedView.getWidth()/2-width/2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//TODO: move into Pointer
|
||||||
|
private int getYBasedOnGravity(int height){
|
||||||
|
int [] pos = new int[2];
|
||||||
|
mHighlightedView.getLocationInWindow(pos);
|
||||||
|
int y = pos[1];
|
||||||
|
if((mPointer.mGravity & Gravity.BOTTOM) == Gravity.BOTTOM){
|
||||||
|
return y+mHighlightedView.getHeight()-height;
|
||||||
|
} else if ((mPointer.mGravity & Gravity.TOP) == Gravity.TOP) {
|
||||||
|
return y;
|
||||||
|
}else { // this is center
|
||||||
|
return y+mHighlightedView.getHeight()/2-height/2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupView(){
|
||||||
|
// TODO: throw exception if either mActivity, mDuration, mHighlightedView is null
|
||||||
|
checking();
|
||||||
|
final ViewTreeObserver viewTreeObserver = mHighlightedView.getViewTreeObserver();
|
||||||
|
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||||
|
@Override
|
||||||
|
public void onGlobalLayout() {
|
||||||
|
// make sure this only run once
|
||||||
|
mHighlightedView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||||
|
|
||||||
|
/* Initialize a frame layout with a hole */
|
||||||
|
mFrameLayout = new FrameLayoutWithHole(mActivity, mHighlightedView, mMotionType, mOverlay);
|
||||||
|
/* handle click disable */
|
||||||
|
handleDisableClicking(mFrameLayout);
|
||||||
|
|
||||||
|
/* setup floating action button */
|
||||||
|
if (mPointer != null) {
|
||||||
|
FloatingActionButton fab = setupAndAddFABToFrameLayout(mFrameLayout);
|
||||||
|
performAnimationOn(fab);
|
||||||
|
}
|
||||||
|
setupFrameLayout();
|
||||||
|
/* setup tooltip view */
|
||||||
|
setupToolTip();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private void checking(){
|
||||||
|
// There is not check for tooltip because tooltip can be null, it means there no tooltip will be shown
|
||||||
|
|
||||||
|
}
|
||||||
|
private void handleDisableClicking(FrameLayoutWithHole frameLayoutWithHole){
|
||||||
|
// 1. if user provides an overlay listener, use that as 1st priority
|
||||||
|
if (mOverlay != null && mOverlay.mOnClickListener!=null) {
|
||||||
|
frameLayoutWithHole.setClickable(true);
|
||||||
|
frameLayoutWithHole.setOnClickListener(mOverlay.mOnClickListener);
|
||||||
|
}
|
||||||
|
// 2. if overlay listener is not provided, check if it's disabled
|
||||||
|
else if (mOverlay != null && mOverlay.mDisableClick) {
|
||||||
|
Log.w("tourguide", "Overlay's default OnClickListener is null, it will proceed to next tourguide when it is clicked");
|
||||||
|
frameLayoutWithHole.setViewHole(mHighlightedView);
|
||||||
|
frameLayoutWithHole.setSoundEffectsEnabled(false);
|
||||||
|
frameLayoutWithHole.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override public void onClick(View v) {} // do nothing, disabled.
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupToolTip(){
|
||||||
|
final FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
|
||||||
|
|
||||||
|
if (mToolTip != null) {
|
||||||
|
/* inflate and get views */
|
||||||
|
ViewGroup parent = (ViewGroup) mActivity.getWindow().getDecorView();
|
||||||
|
LayoutInflater layoutInflater = mActivity.getLayoutInflater();
|
||||||
|
mToolTipViewGroup = layoutInflater.inflate(R.layout.tooltip, null);
|
||||||
|
View toolTipContainer = mToolTipViewGroup.findViewById(R.id.toolTip_container);
|
||||||
|
TextView toolTipTitleTV = (TextView) mToolTipViewGroup.findViewById(R.id.title);
|
||||||
|
TextView toolTipDescriptionTV = (TextView) mToolTipViewGroup.findViewById(R.id.description);
|
||||||
|
|
||||||
|
/* set tooltip attributes */
|
||||||
|
toolTipContainer.setBackgroundColor(mToolTip.mBackgroundColor);
|
||||||
|
if (mToolTip.mTitle == null){
|
||||||
|
toolTipTitleTV.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
toolTipTitleTV.setText(mToolTip.mTitle);
|
||||||
|
}
|
||||||
|
if (mToolTip.mDescription == null){
|
||||||
|
toolTipDescriptionTV.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
toolTipDescriptionTV.setText(mToolTip.mDescription);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mToolTipViewGroup.startAnimation(mToolTip.mEnterAnimation);
|
||||||
|
|
||||||
|
/* add setShadow if it's turned on */
|
||||||
|
if (mToolTip.mShadow) {
|
||||||
|
mToolTipViewGroup.setBackgroundDrawable(mActivity.getResources().getDrawable(R.drawable.drop_shadow));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* position and size calculation */
|
||||||
|
int [] pos = new int[2];
|
||||||
|
mHighlightedView.getLocationOnScreen(pos);
|
||||||
|
int targetViewX = pos[0];
|
||||||
|
final int targetViewY = pos[1];
|
||||||
|
|
||||||
|
// get measured size of tooltip
|
||||||
|
mToolTipViewGroup.measure(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
|
||||||
|
int toolTipMeasuredWidth = mToolTipViewGroup.getMeasuredWidth();
|
||||||
|
int toolTipMeasuredHeight = mToolTipViewGroup.getMeasuredHeight();
|
||||||
|
|
||||||
|
Point resultPoint = new Point(); // this holds the final position of tooltip
|
||||||
|
float density = mActivity.getResources().getDisplayMetrics().density;
|
||||||
|
final float adjustment = 10 * density; //adjustment is that little overlapping area of tooltip and targeted button
|
||||||
|
|
||||||
|
// calculate x position, based on gravity, tooltipMeasuredWidth, parent max width, x position of target view, adjustment
|
||||||
|
if (toolTipMeasuredWidth > parent.getWidth()){
|
||||||
|
resultPoint.x = getXForTooTip(mToolTip.mGravity, parent.getWidth(), targetViewX, adjustment);
|
||||||
|
} else {
|
||||||
|
resultPoint.x = getXForTooTip(mToolTip.mGravity, toolTipMeasuredWidth, targetViewX, adjustment);
|
||||||
|
}
|
||||||
|
|
||||||
|
resultPoint.y = getYForTooTip(mToolTip.mGravity, toolTipMeasuredHeight, targetViewY, adjustment);
|
||||||
|
|
||||||
|
// add view to parent
|
||||||
|
// ((ViewGroup) mActivity.getWindow().getDecorView().findViewById(android.R.id.content)).addView(mToolTipViewGroup, layoutParams);
|
||||||
|
parent.addView(mToolTipViewGroup, layoutParams);
|
||||||
|
|
||||||
|
// 1. width < screen check
|
||||||
|
if (toolTipMeasuredWidth > parent.getWidth()){
|
||||||
|
mToolTipViewGroup.getLayoutParams().width = parent.getWidth();
|
||||||
|
toolTipMeasuredWidth = parent.getWidth();
|
||||||
|
}
|
||||||
|
// 2. x left boundary check
|
||||||
|
if (resultPoint.x < 0){
|
||||||
|
mToolTipViewGroup.getLayoutParams().width = toolTipMeasuredWidth + resultPoint.x; //since point.x is negative, use plus
|
||||||
|
resultPoint.x = 0;
|
||||||
|
}
|
||||||
|
// 3. x right boundary check
|
||||||
|
int tempRightX = resultPoint.x + toolTipMeasuredWidth;
|
||||||
|
if ( tempRightX > parent.getWidth()){
|
||||||
|
mToolTipViewGroup.getLayoutParams().width = parent.getWidth() - resultPoint.x; //since point.x is negative, use plus
|
||||||
|
}
|
||||||
|
|
||||||
|
// pass toolTip onClickListener into toolTipViewGroup
|
||||||
|
if (mToolTip.mOnClickListener!=null) {
|
||||||
|
mToolTipViewGroup.setOnClickListener(mToolTip.mOnClickListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: no boundary check for height yet, this is a unlikely case though
|
||||||
|
// height boundary can be fixed by user changing the gravity to the other size, since there are plenty of space vertically compared to horizontally
|
||||||
|
|
||||||
|
// this needs an viewTreeObserver, that's because TextView measurement of it's vertical height is not accurate (didn't take into account of multiple lines yet) before it's rendered
|
||||||
|
// re-calculate height again once it's rendered
|
||||||
|
final ViewTreeObserver viewTreeObserver = mToolTipViewGroup.getViewTreeObserver();
|
||||||
|
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||||
|
@Override
|
||||||
|
public void onGlobalLayout() {
|
||||||
|
mToolTipViewGroup.getViewTreeObserver().removeGlobalOnLayoutListener(this);// make sure this only run once
|
||||||
|
|
||||||
|
int fixedY;
|
||||||
|
int toolTipHeightAfterLayouted = mToolTipViewGroup.getHeight();
|
||||||
|
fixedY = getYForTooTip(mToolTip.mGravity, toolTipHeightAfterLayouted, targetViewY, adjustment);
|
||||||
|
layoutParams.setMargins((int)mToolTipViewGroup.getX(),fixedY,0,0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// set the position using setMargins on the left and top
|
||||||
|
layoutParams.setMargins(resultPoint.x, resultPoint.y, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getXForTooTip(int gravity, int toolTipMeasuredWidth, int targetViewX, float adjustment){
|
||||||
|
int x;
|
||||||
|
if ((gravity & Gravity.LEFT) == Gravity.LEFT){
|
||||||
|
x = targetViewX - toolTipMeasuredWidth + (int)adjustment;
|
||||||
|
} else if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
|
||||||
|
x = targetViewX + mHighlightedView.getWidth() - (int)adjustment;
|
||||||
|
} else {
|
||||||
|
x = targetViewX + mHighlightedView.getWidth() / 2 - toolTipMeasuredWidth / 2;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
private int getYForTooTip(int gravity, int toolTipMeasuredHeight, int targetViewY, float adjustment){
|
||||||
|
int y;
|
||||||
|
if ((gravity & Gravity.TOP) == Gravity.TOP) {
|
||||||
|
|
||||||
|
if (((gravity & Gravity.LEFT) == Gravity.LEFT) || ((gravity & Gravity.RIGHT) == Gravity.RIGHT)) {
|
||||||
|
y = targetViewY - toolTipMeasuredHeight + (int)adjustment;
|
||||||
|
} else {
|
||||||
|
y = targetViewY - toolTipMeasuredHeight - (int)adjustment;
|
||||||
|
}
|
||||||
|
} else if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
|
||||||
|
if (((gravity & Gravity.LEFT) == Gravity.LEFT) || ((gravity & Gravity.RIGHT) == Gravity.RIGHT)) {
|
||||||
|
y = targetViewY + mHighlightedView.getHeight() - (int) adjustment;
|
||||||
|
} else {
|
||||||
|
y = targetViewY + mHighlightedView.getHeight() + (int) adjustment;
|
||||||
|
}
|
||||||
|
} else { // this is center
|
||||||
|
if (((gravity & Gravity.LEFT) == Gravity.LEFT) || ((gravity & Gravity.RIGHT) == Gravity.RIGHT)) {
|
||||||
|
y = targetViewY + mHighlightedView.getHeight() / 2 - (int) adjustment;
|
||||||
|
} else {
|
||||||
|
y = targetViewY + mHighlightedView.getHeight() / 2 + (int) adjustment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FloatingActionButton setupAndAddFABToFrameLayout(final FrameLayoutWithHole frameLayoutWithHole){
|
||||||
|
// invisFab is invisible, and it's only used for getting the width and height
|
||||||
|
final FloatingActionButton invisFab = new FloatingActionButton(mActivity);
|
||||||
|
invisFab.setSize(FloatingActionButton.SIZE_MINI);
|
||||||
|
invisFab.setVisibility(View.INVISIBLE);
|
||||||
|
((ViewGroup)mActivity.getWindow().getDecorView()).addView(invisFab);
|
||||||
|
|
||||||
|
// fab is the real fab that is going to be added
|
||||||
|
final FloatingActionButton fab = new FloatingActionButton(mActivity);
|
||||||
|
fab.setBackgroundColor(Color.BLUE);
|
||||||
|
fab.setSize(FloatingActionButton.SIZE_MINI);
|
||||||
|
fab.setColorNormal(mPointer.mColor);
|
||||||
|
fab.setStrokeVisible(false);
|
||||||
|
fab.setClickable(false);
|
||||||
|
|
||||||
|
// When invisFab is layouted, it's width and height can be used to calculate the correct position of fab
|
||||||
|
final ViewTreeObserver viewTreeObserver = invisFab.getViewTreeObserver();
|
||||||
|
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||||
|
@Override
|
||||||
|
public void onGlobalLayout() {
|
||||||
|
// make sure this only run once
|
||||||
|
invisFab.getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||||
|
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||||
|
frameLayoutWithHole.addView(fab, params);
|
||||||
|
|
||||||
|
// measure size of image to be placed
|
||||||
|
params.setMargins(getXBasedOnGravity(invisFab.getWidth()), getYBasedOnGravity(invisFab.getHeight()), 0, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return fab;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupFrameLayout(){
|
||||||
|
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
|
||||||
|
ViewGroup contentArea = (ViewGroup) mActivity.getWindow().getDecorView().findViewById(android.R.id.content);
|
||||||
|
int [] pos = new int[2];
|
||||||
|
contentArea.getLocationOnScreen(pos);
|
||||||
|
// frameLayoutWithHole's coordinates are calculated taking full screen height into account
|
||||||
|
// but we're adding it to the content area only, so we need to offset it to the same Y value of contentArea
|
||||||
|
|
||||||
|
layoutParams.setMargins(0,-pos[1],0,0);
|
||||||
|
contentArea.addView(mFrameLayout, layoutParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performAnimationOn(final View view){
|
||||||
|
|
||||||
|
if (mTechnique != null && mTechnique == Technique.HorizontalLeft){
|
||||||
|
|
||||||
|
final AnimatorSet animatorSet = new AnimatorSet();
|
||||||
|
final AnimatorSet animatorSet2 = new AnimatorSet();
|
||||||
|
Animator.AnimatorListener lis1 = new Animator.AnimatorListener() {
|
||||||
|
@Override public void onAnimationStart(Animator animator) {}
|
||||||
|
@Override public void onAnimationCancel(Animator animator) {}
|
||||||
|
@Override public void onAnimationRepeat(Animator animator) {}
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animator) {
|
||||||
|
view.setScaleX(1f);
|
||||||
|
view.setScaleY(1f);
|
||||||
|
view.setTranslationX(0);
|
||||||
|
animatorSet2.start();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Animator.AnimatorListener lis2 = new Animator.AnimatorListener() {
|
||||||
|
@Override public void onAnimationStart(Animator animator) {}
|
||||||
|
@Override public void onAnimationCancel(Animator animator) {}
|
||||||
|
@Override public void onAnimationRepeat(Animator animator) {}
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animator) {
|
||||||
|
view.setScaleX(1f);
|
||||||
|
view.setScaleY(1f);
|
||||||
|
view.setTranslationX(0);
|
||||||
|
animatorSet.start();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
long fadeInDuration = 800;
|
||||||
|
long scaleDownDuration = 800;
|
||||||
|
long goLeftXDuration = 2000;
|
||||||
|
long fadeOutDuration = goLeftXDuration;
|
||||||
|
float translationX = getScreenWidth()/2;
|
||||||
|
|
||||||
|
final ValueAnimator fadeInAnim = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);
|
||||||
|
fadeInAnim.setDuration(fadeInDuration);
|
||||||
|
final ObjectAnimator scaleDownX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.85f);
|
||||||
|
scaleDownX.setDuration(scaleDownDuration);
|
||||||
|
final ObjectAnimator scaleDownY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.85f);
|
||||||
|
scaleDownY.setDuration(scaleDownDuration);
|
||||||
|
final ObjectAnimator goLeftX = ObjectAnimator.ofFloat(view, "translationX", -translationX);
|
||||||
|
goLeftX.setDuration(goLeftXDuration);
|
||||||
|
final ValueAnimator fadeOutAnim = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f);
|
||||||
|
fadeOutAnim.setDuration(fadeOutDuration);
|
||||||
|
|
||||||
|
final ValueAnimator fadeInAnim2 = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);
|
||||||
|
fadeInAnim2.setDuration(fadeInDuration);
|
||||||
|
final ObjectAnimator scaleDownX2 = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.85f);
|
||||||
|
scaleDownX2.setDuration(scaleDownDuration);
|
||||||
|
final ObjectAnimator scaleDownY2 = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.85f);
|
||||||
|
scaleDownY2.setDuration(scaleDownDuration);
|
||||||
|
final ObjectAnimator goLeftX2 = ObjectAnimator.ofFloat(view, "translationX", -translationX);
|
||||||
|
goLeftX2.setDuration(goLeftXDuration);
|
||||||
|
final ValueAnimator fadeOutAnim2 = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f);
|
||||||
|
fadeOutAnim2.setDuration(fadeOutDuration);
|
||||||
|
|
||||||
|
animatorSet.play(fadeInAnim);
|
||||||
|
animatorSet.play(scaleDownX).with(scaleDownY).after(fadeInAnim);
|
||||||
|
animatorSet.play(goLeftX).with(fadeOutAnim).after(scaleDownY);
|
||||||
|
|
||||||
|
animatorSet2.play(fadeInAnim2);
|
||||||
|
animatorSet2.play(scaleDownX2).with(scaleDownY2).after(fadeInAnim2);
|
||||||
|
animatorSet2.play(goLeftX2).with(fadeOutAnim2).after(scaleDownY2);
|
||||||
|
|
||||||
|
animatorSet.addListener(lis1);
|
||||||
|
animatorSet2.addListener(lis2);
|
||||||
|
animatorSet.start();
|
||||||
|
|
||||||
|
/* these animatorSets are kept track in FrameLayout, so that they can be cleaned up when FrameLayout is detached from window */
|
||||||
|
mFrameLayout.addAnimatorSet(animatorSet);
|
||||||
|
mFrameLayout.addAnimatorSet(animatorSet2);
|
||||||
|
} else if (mTechnique != null && mTechnique == Technique.HorizontalRight){
|
||||||
|
|
||||||
|
} else if (mTechnique != null && mTechnique == Technique.VerticalUpward){
|
||||||
|
|
||||||
|
} else if (mTechnique != null && mTechnique == Technique.VerticalDownward){
|
||||||
|
|
||||||
|
} else { // do click for default case
|
||||||
|
final AnimatorSet animatorSet = new AnimatorSet();
|
||||||
|
final AnimatorSet animatorSet2 = new AnimatorSet();
|
||||||
|
Animator.AnimatorListener lis1 = new Animator.AnimatorListener() {
|
||||||
|
@Override public void onAnimationStart(Animator animator) {}
|
||||||
|
@Override public void onAnimationCancel(Animator animator) {}
|
||||||
|
@Override public void onAnimationRepeat(Animator animator) {}
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animator) {
|
||||||
|
view.setScaleX(1f);
|
||||||
|
view.setScaleY(1f);
|
||||||
|
view.setTranslationX(0);
|
||||||
|
animatorSet2.start();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Animator.AnimatorListener lis2 = new Animator.AnimatorListener() {
|
||||||
|
@Override public void onAnimationStart(Animator animator) {}
|
||||||
|
@Override public void onAnimationCancel(Animator animator) {}
|
||||||
|
@Override public void onAnimationRepeat(Animator animator) {}
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animator) {
|
||||||
|
view.setScaleX(1f);
|
||||||
|
view.setScaleY(1f);
|
||||||
|
view.setTranslationX(0);
|
||||||
|
animatorSet.start();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
long fadeInDuration = 800;
|
||||||
|
long scaleDownDuration = 800;
|
||||||
|
long fadeOutDuration = 800;
|
||||||
|
long delay = 1000;
|
||||||
|
|
||||||
|
final ValueAnimator delayAnim = ObjectAnimator.ofFloat(view, "translationX", 0);
|
||||||
|
delayAnim.setDuration(delay);
|
||||||
|
final ValueAnimator fadeInAnim = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);
|
||||||
|
fadeInAnim.setDuration(fadeInDuration);
|
||||||
|
final ObjectAnimator scaleDownX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.85f);
|
||||||
|
scaleDownX.setDuration(scaleDownDuration);
|
||||||
|
final ObjectAnimator scaleDownY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.85f);
|
||||||
|
scaleDownY.setDuration(scaleDownDuration);
|
||||||
|
final ObjectAnimator scaleUpX = ObjectAnimator.ofFloat(view, "scaleX", 0.85f, 1f);
|
||||||
|
scaleUpX.setDuration(scaleDownDuration);
|
||||||
|
final ObjectAnimator scaleUpY = ObjectAnimator.ofFloat(view, "scaleY", 0.85f, 1f);
|
||||||
|
scaleUpY.setDuration(scaleDownDuration);
|
||||||
|
final ValueAnimator fadeOutAnim = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f);
|
||||||
|
fadeOutAnim.setDuration(fadeOutDuration);
|
||||||
|
|
||||||
|
final ValueAnimator delayAnim2 = ObjectAnimator.ofFloat(view, "translationX", 0);
|
||||||
|
delayAnim2.setDuration(delay);
|
||||||
|
final ValueAnimator fadeInAnim2 = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);
|
||||||
|
fadeInAnim2.setDuration(fadeInDuration);
|
||||||
|
final ObjectAnimator scaleDownX2 = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.85f);
|
||||||
|
scaleDownX2.setDuration(scaleDownDuration);
|
||||||
|
final ObjectAnimator scaleDownY2 = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.85f);
|
||||||
|
scaleDownY2.setDuration(scaleDownDuration);
|
||||||
|
final ObjectAnimator scaleUpX2 = ObjectAnimator.ofFloat(view, "scaleX", 0.85f, 1f);
|
||||||
|
scaleUpX2.setDuration(scaleDownDuration);
|
||||||
|
final ObjectAnimator scaleUpY2 = ObjectAnimator.ofFloat(view, "scaleY", 0.85f, 1f);
|
||||||
|
scaleUpY2.setDuration(scaleDownDuration);
|
||||||
|
final ValueAnimator fadeOutAnim2 = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f);
|
||||||
|
fadeOutAnim2.setDuration(fadeOutDuration);
|
||||||
|
view.setAlpha(0);
|
||||||
|
animatorSet.setStartDelay(mToolTip != null ? mToolTip.mEnterAnimation.getDuration() : 0);
|
||||||
|
animatorSet.play(fadeInAnim);
|
||||||
|
animatorSet.play(scaleDownX).with(scaleDownY).after(fadeInAnim);
|
||||||
|
animatorSet.play(scaleUpX).with(scaleUpY).with(fadeOutAnim).after(scaleDownY);
|
||||||
|
animatorSet.play(delayAnim).after(scaleUpY);
|
||||||
|
|
||||||
|
animatorSet2.play(fadeInAnim2);
|
||||||
|
animatorSet2.play(scaleDownX2).with(scaleDownY2).after(fadeInAnim2);
|
||||||
|
animatorSet2.play(scaleUpX2).with(scaleUpY2).with(fadeOutAnim2).after(scaleDownY2);
|
||||||
|
animatorSet2.play(delayAnim2).after(scaleUpY2);
|
||||||
|
|
||||||
|
animatorSet.addListener(lis1);
|
||||||
|
animatorSet2.addListener(lis2);
|
||||||
|
animatorSet.start();
|
||||||
|
|
||||||
|
/* these animatorSets are kept track in FrameLayout, so that they can be cleaned up when FrameLayout is detached from window */
|
||||||
|
mFrameLayout.addAnimatorSet(animatorSet);
|
||||||
|
mFrameLayout.addAnimatorSet(animatorSet2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private int getScreenWidth(){
|
||||||
|
if (mActivity!=null) {
|
||||||
|
return mActivity.getResources().getDisplayMetrics().widthPixels;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user