mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-07-13 17:51:57 +00:00
add multiple steps to tutorialViews
This commit is contained in:
parent
e561e2db30
commit
b9e07e4573
14 changed files with 272 additions and 61 deletions
BIN
Habitica/res/drawable-hdpi/speechbubble_caret.png
Normal file
BIN
Habitica/res/drawable-hdpi/speechbubble_caret.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 618 B |
BIN
Habitica/res/drawable-mdpi/speechbubble_caret.png
Normal file
BIN
Habitica/res/drawable-mdpi/speechbubble_caret.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 478 B |
BIN
Habitica/res/drawable-xhdpi/speechbubble_caret.png
Normal file
BIN
Habitica/res/drawable-xhdpi/speechbubble_caret.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 738 B |
BIN
Habitica/res/drawable-xxhdpi/speechbubble_caret.png
Normal file
BIN
Habitica/res/drawable-xxhdpi/speechbubble_caret.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 951 B |
|
|
@ -1,26 +1,29 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:fitsSystemWindows="true"
|
android:fitsSystemWindows="true"
|
||||||
android:id="@+id/background">
|
android:id="@+id/background">
|
||||||
<View android:layout_height="match_parent"
|
<View android:layout_height="match_parent"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:background="@android:color/black"
|
android:background="@android:color/black"
|
||||||
android:alpha="0.6"/>
|
android:alpha="0.6"/>
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:paddingBottom="24dp"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
android:layout_marginBottom="?actionBarSize">
|
||||||
|
<com.habitrpg.android.habitica.ui.SpeechBubbleView
|
||||||
|
android:id="@+id/speech_bubble"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="16dp"
|
app:namePlate="Justin"
|
||||||
android:layout_alignParentBottom="true"
|
app:npcDrawable="@drawable/justin_textbox"/>
|
||||||
android:fitsSystemWindows="true"
|
|
||||||
android:layout_marginBottom="?actionBarSize">
|
|
||||||
<com.habitrpg.android.habitica.ui.SpeechBubbleView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:namePlate="Justin"
|
|
||||||
app:npcDrawable="@drawable/justin_textbox"/>
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
|
||||||
|
|
@ -19,16 +19,16 @@
|
||||||
android:layout_marginTop="46dp"
|
android:layout_marginTop="46dp"
|
||||||
android:background="@drawable/white_rounded_bg"
|
android:background="@drawable/white_rounded_bg"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingBottom="14dp"
|
android:paddingBottom="16dp"
|
||||||
android:paddingLeft="21dp"
|
android:paddingLeft="21dp"
|
||||||
android:paddingRight="21dp"
|
android:paddingRight="21dp"
|
||||||
android:paddingTop="16dp">
|
android:paddingTop="24dp"
|
||||||
|
android:layout_marginBottom="10dp">
|
||||||
|
|
||||||
<TextView
|
<com.habitrpg.android.habitica.ui.views.Typewriter
|
||||||
android:id="@+id/textView"
|
android:id="@+id/textView"
|
||||||
style="@style/Body1"
|
style="@style/Subheader1"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
tools:text="@string/welcome_text" />
|
tools:text="@string/welcome_text" />
|
||||||
|
|
||||||
|
|
@ -37,7 +37,8 @@
|
||||||
style="?android:attr/buttonBarStyle"
|
style="?android:attr/buttonBarStyle"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginTop="8dp">
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/dismissButton"
|
android:id="@+id/dismissButton"
|
||||||
|
|
@ -61,6 +62,15 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/continue_indicator"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/speechbubble_caret"
|
||||||
|
android:layout_gravity="bottom|center"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/name_plate"
|
android:id="@+id/name_plate"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,16 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="tutorial_habits">Complete Positive Habits to earn gold and experience! Negative Habits will hurt your avatar if you tap them, so avoid them in real life!</string>
|
<string name="tutorial_overview">Here we are! I’ve filled out some tasks for you based on your interests. Try adding a few of your own. You can edit any task by tapping the title.</string>
|
||||||
<string name="tutorial_dailies">Defeat your repeating Daily tasks to gain gold and experience. Danger! Dailies will hurt your avatar if you don\'t complete them in time.</string>
|
<string name="tutorial_habits_1">First up is Habits. They can be positive Habits you want to improve or negative Habits you want to quit.</string>
|
||||||
<string name="tutorial_todos">Complete your To-Dos in real life, then check them off for GOLD and EXPERIENCE so you can earn Rewards and unlock new features!</string>
|
<string name="tutorial_habits_2">Every time you do a positive Habit, tap the + to get experience and gold!</string>
|
||||||
<string name="tutorial_rewards">These are your Rewards! Earn gold by completing real-world Habits, Dailies, and To-Dos. Then spend it on in-game Rewards or custom real-world Rewards!</string>
|
<string name="tutorial_habits_3">If you slip up and do a negative Habit, tapping the - will reduce your avatar’s health to help you stay accountable.</string>
|
||||||
|
<string name="tutorial_habits_4">Give it a shot! You can explore the other task types through the bottom navigation.</string>
|
||||||
|
<string name="tutorial_dailies_1">Make Dailies for time sensitive tasks that need to be done on a regular schedule.</string>
|
||||||
|
<string name="tutorial_dailies_2">Be careful — if you miss one, your avatar will take damage overnight. Checking them off consistently brings great rewards!</string>
|
||||||
|
<string name="tutorial_todos_1">Use To-dos to keep track of tasks you need to do just once.</string>
|
||||||
|
<string name="tutorial_todos_2">If your To-do has to be done by a certain time, set a due date. Looks like you can check one off — go ahead!</string>
|
||||||
|
<string name="tutorial_rewards_1">Buy gear for your avatar with the gold you earn!</string>
|
||||||
|
<string name="tutorial_rewards_2">You can also make real-world Custom Rewards based on what motivates you.</string>
|
||||||
|
|
||||||
<string name="tutorial_equipment">When you buy equipment, it appears here. Your Battle Gear affects your stats, and your Costume (if enabled) affects what your avatar wears.</string>
|
<string name="tutorial_equipment">When you buy equipment, it appears here. Your Battle Gear affects your stats, and your Costume (if enabled) affects what your avatar wears.</string>
|
||||||
<string name="tutorial_items">Earn items by completing tasks and leveling up. Tap on an item to use it!</string>
|
<string name="tutorial_items">Earn items by completing tasks and leveling up. Tap on an item to use it!</string>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ package com.habitrpg.android.habitica.events;
|
||||||
|
|
||||||
import com.magicmicky.habitrpgwrapper.lib.models.TutorialStep;
|
import com.magicmicky.habitrpgwrapper.lib.models.TutorialStep;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by viirus on 26/01/16.
|
* Created by viirus on 26/01/16.
|
||||||
*/
|
*/
|
||||||
|
|
@ -10,4 +12,5 @@ public class DisplayTutorialEvent {
|
||||||
public TutorialStep step;
|
public TutorialStep step;
|
||||||
public String tutorialText;
|
public String tutorialText;
|
||||||
|
|
||||||
|
public List<String> tutorialTexts;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.habitrpg.android.habitica.ui;
|
||||||
|
|
||||||
|
|
||||||
import com.habitrpg.android.habitica.R;
|
import com.habitrpg.android.habitica.R;
|
||||||
|
import com.habitrpg.android.habitica.ui.views.Typewriter;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
|
|
@ -9,6 +10,8 @@ import android.graphics.drawable.Drawable;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.animation.Animation;
|
||||||
|
import android.view.animation.AnimationUtils;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
@ -16,13 +19,13 @@ import android.widget.TextView;
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
public class SpeechBubbleView extends FrameLayout {
|
public class SpeechBubbleView extends FrameLayout implements View.OnClickListener {
|
||||||
|
|
||||||
@BindView(R.id.name_plate)
|
@BindView(R.id.name_plate)
|
||||||
TextView namePlate;
|
TextView namePlate;
|
||||||
|
|
||||||
@BindView(R.id.textView)
|
@BindView(R.id.textView)
|
||||||
TextView textView;
|
Typewriter textView;
|
||||||
|
|
||||||
@BindView(R.id.npc_image_view)
|
@BindView(R.id.npc_image_view)
|
||||||
ImageView npcImageView;
|
ImageView npcImageView;
|
||||||
|
|
@ -30,6 +33,10 @@ public class SpeechBubbleView extends FrameLayout {
|
||||||
@BindView(R.id.confirmation_buttons)
|
@BindView(R.id.confirmation_buttons)
|
||||||
ViewGroup confirmationButtons;
|
ViewGroup confirmationButtons;
|
||||||
|
|
||||||
|
@BindView(R.id.continue_indicator)
|
||||||
|
View continueIndicator;
|
||||||
|
private ShowNextListener showNextListener;
|
||||||
|
|
||||||
public SpeechBubbleView(Context context, AttributeSet attrs) {
|
public SpeechBubbleView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
|
||||||
|
|
@ -51,7 +58,43 @@ public class SpeechBubbleView extends FrameLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
confirmationButtons.setVisibility(View.GONE);
|
confirmationButtons.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
this.setOnClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setConfirmationButtonVisibility(int visibility) {
|
||||||
|
confirmationButtons.setVisibility(visibility);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void animateText(String text) {
|
||||||
|
this.textView.animateText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setText(String text) {
|
||||||
|
this.textView.setText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHasMoreContent(Boolean hasMoreContent) {
|
||||||
|
continueIndicator.setVisibility(hasMoreContent ? View.VISIBLE : View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShowNextListener(ShowNextListener listener) {
|
||||||
|
showNextListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (textView.isAnimating()) {
|
||||||
|
textView.stopTextAnimation();
|
||||||
|
} else {
|
||||||
|
if (showNextListener != null) {
|
||||||
|
showNextListener.showNextStep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ShowNextListener {
|
||||||
|
void showNextStep();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,63 +1,103 @@
|
||||||
package com.habitrpg.android.habitica.ui;
|
package com.habitrpg.android.habitica.ui;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.RelativeLayout;
|
||||||
|
|
||||||
import com.habitrpg.android.habitica.R;
|
import com.habitrpg.android.habitica.R;
|
||||||
import com.magicmicky.habitrpgwrapper.lib.models.TutorialStep;
|
import com.magicmicky.habitrpgwrapper.lib.models.TutorialStep;
|
||||||
|
|
||||||
import android.content.Context;
|
import java.util.List;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.RelativeLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
import butterknife.OnClick;
|
||||||
|
|
||||||
public class TutorialView extends FrameLayout implements View.OnClickListener {
|
public class TutorialView extends FrameLayout {
|
||||||
|
|
||||||
public TutorialStep step;
|
public TutorialStep step;
|
||||||
|
@Nullable
|
||||||
public OnTutorialReaction onReaction;
|
public OnTutorialReaction onReaction;
|
||||||
@BindView(R.id.textView)
|
@BindView(R.id.speech_bubble)
|
||||||
TextView tutorialTextView;
|
SpeechBubbleView speechBubbleView;
|
||||||
@BindView(R.id.background)
|
@BindView(R.id.background)
|
||||||
RelativeLayout background;
|
RelativeLayout background;
|
||||||
@BindView(R.id.dismissButton)
|
@BindView(R.id.dismissButton)
|
||||||
Button dismissButton;
|
Button dismissButton;
|
||||||
@BindView(R.id.completeButton)
|
@BindView(R.id.completeButton)
|
||||||
Button completeButton;
|
Button completeButton;
|
||||||
@BindView(R.id.confirmation_buttons)
|
|
||||||
ViewGroup confirmationButtons;
|
|
||||||
|
|
||||||
public TutorialView(Context context, TutorialStep step, OnTutorialReaction onReaction) {
|
private List<String> tutorialTexts;
|
||||||
|
private int currentTextIndex;
|
||||||
|
|
||||||
|
public TutorialView(Context context, TutorialStep step, @Nullable OnTutorialReaction onReaction) {
|
||||||
super(context);
|
super(context);
|
||||||
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
mInflater.inflate(R.layout.overlay_tutorial, this, true);
|
mInflater.inflate(R.layout.overlay_tutorial, this, true);
|
||||||
ButterKnife.bind(this);
|
ButterKnife.bind(this);
|
||||||
background.setOnClickListener(this);
|
speechBubbleView.setConfirmationButtonVisibility(View.GONE);
|
||||||
dismissButton.setOnClickListener(this);
|
speechBubbleView.setShowNextListener(this::displayNextTutorialText);
|
||||||
completeButton.setOnClickListener(this);
|
|
||||||
confirmationButtons.setVisibility(View.VISIBLE);
|
|
||||||
this.step = step;
|
this.step = step;
|
||||||
this.onReaction = onReaction;
|
this.onReaction = onReaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTutorialText(String text) {
|
public void setTutorialText(String text) {
|
||||||
this.tutorialTextView.setText(text);
|
this.speechBubbleView.animateText(text);
|
||||||
|
speechBubbleView.setConfirmationButtonVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void setTutorialTexts(List<String> texts) {
|
||||||
public void onClick(View v) {
|
tutorialTexts = texts;
|
||||||
if (Objects.equals(v, background) || Objects.equals(v, completeButton)) {
|
currentTextIndex = -1;
|
||||||
|
displayNextTutorialText();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displayNextTutorialText() {
|
||||||
|
currentTextIndex++;
|
||||||
|
if (currentTextIndex < tutorialTexts.size()) {
|
||||||
|
speechBubbleView.animateText(tutorialTexts.get(currentTextIndex));
|
||||||
|
if (isDisplayingLastStep()) {
|
||||||
|
speechBubbleView.setConfirmationButtonVisibility(View.VISIBLE);
|
||||||
|
speechBubbleView.setHasMoreContent(false);
|
||||||
|
} else {
|
||||||
|
speechBubbleView.setHasMoreContent(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.completeButton)
|
||||||
|
public void completeButtonClicked() {
|
||||||
|
if (this.onReaction != null) {
|
||||||
this.onReaction.onTutorialCompleted(this.step);
|
this.onReaction.onTutorialCompleted(this.step);
|
||||||
} else if (Objects.equals(v, dismissButton)) {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.dismissButton)
|
||||||
|
public void dismissButtonClicked() {
|
||||||
|
if (this.onReaction != null) {
|
||||||
this.onReaction.onTutorialDeferred(this.step);
|
this.onReaction.onTutorialDeferred(this.step);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.background)
|
||||||
|
public void backgroundClicked() {
|
||||||
|
if (isDisplayingLastStep()) {
|
||||||
|
if (this.onReaction != null) {
|
||||||
|
this.onReaction.onTutorialCompleted(this.step);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
speechBubbleView.onClick(speechBubbleView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDisplayingLastStep() {
|
||||||
|
return currentTextIndex == (tutorialTexts.size()-1);
|
||||||
|
}
|
||||||
|
|
||||||
public interface OnTutorialReaction {
|
public interface OnTutorialReaction {
|
||||||
void onTutorialCompleted(TutorialStep step);
|
void onTutorialCompleted(TutorialStep step);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -869,7 +869,11 @@ public class MainActivity extends BaseActivity implements Action1<Throwable>, Ha
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onEvent(DisplayTutorialEvent tutorialEvent) {
|
public void onEvent(DisplayTutorialEvent tutorialEvent) {
|
||||||
this.displayTutorialStep(tutorialEvent.step, tutorialEvent.tutorialText);
|
if (tutorialEvent.tutorialText != null) {
|
||||||
|
this.displayTutorialStep(tutorialEvent.step, tutorialEvent.tutorialText);
|
||||||
|
} else {
|
||||||
|
this.displayTutorialStep(tutorialEvent.step, tutorialEvent.tutorialTexts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
|
|
@ -1091,6 +1095,20 @@ public class MainActivity extends BaseActivity implements Action1<Throwable>, Ha
|
||||||
AmplitudeManager.sendEvent("tutorial", AmplitudeManager.EVENT_CATEGORY_BEHAVIOUR, AmplitudeManager.EVENT_HITTYPE_EVENT, additionalData);
|
AmplitudeManager.sendEvent("tutorial", AmplitudeManager.EVENT_CATEGORY_BEHAVIOUR, AmplitudeManager.EVENT_HITTYPE_EVENT, additionalData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void displayTutorialStep(TutorialStep step, List<String> texts) {
|
||||||
|
TutorialView view = new TutorialView(this, step, this);
|
||||||
|
view.setTutorialTexts(texts);
|
||||||
|
view.onReaction = this;
|
||||||
|
this.overlayLayout.addView(view);
|
||||||
|
this.activeTutorialView = view;
|
||||||
|
|
||||||
|
Map<String, Object> additionalData = new HashMap<>();
|
||||||
|
additionalData.put("eventLabel", step.getIdentifier() + "-android");
|
||||||
|
additionalData.put("eventValue", step.getIdentifier());
|
||||||
|
additionalData.put("complete", false);
|
||||||
|
AmplitudeManager.sendEvent("tutorial", AmplitudeManager.EVENT_CATEGORY_BEHAVIOUR, AmplitudeManager.EVENT_HITTYPE_EVENT, additionalData);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTutorialCompleted(TutorialStep step) {
|
public void onTutorialCompleted(TutorialStep step) {
|
||||||
String path = "flags.tutorial." + step.getTutorialGroup() + "." + step.getIdentifier();
|
String path = "flags.tutorial." + step.getTutorialGroup() + "." + step.getIdentifier();
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import org.greenrobot.eventbus.EventBusException;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
|
@ -41,7 +42,11 @@ public abstract class BaseFragment extends DialogFragment {
|
||||||
if (step != null && !step.getWasCompleted() && (step.getDisplayedOn() == null || (new Date().getTime() - step.getDisplayedOn().getTime()) > 86400000)) {
|
if (step != null && !step.getWasCompleted() && (step.getDisplayedOn() == null || (new Date().getTime() - step.getDisplayedOn().getTime()) > 86400000)) {
|
||||||
DisplayTutorialEvent event = new DisplayTutorialEvent();
|
DisplayTutorialEvent event = new DisplayTutorialEvent();
|
||||||
event.step = step;
|
event.step = step;
|
||||||
event.tutorialText = tutorialText;
|
if (tutorialText != null) {
|
||||||
|
event.tutorialText = tutorialText;
|
||||||
|
} else {
|
||||||
|
event.tutorialTexts = tutorialTexts;
|
||||||
|
}
|
||||||
EventBus.getDefault().post(event);
|
EventBus.getDefault().post(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -56,6 +61,7 @@ public abstract class BaseFragment extends DialogFragment {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
public List<String> tutorialTexts;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
|
||||||
import org.greenrobot.eventbus.EventBus;
|
import org.greenrobot.eventbus.EventBus;
|
||||||
import org.greenrobot.eventbus.Subscribe;
|
import org.greenrobot.eventbus.Subscribe;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
||||||
|
|
@ -100,22 +102,29 @@ public class TaskRecyclerViewFragment extends BaseFragment implements View.OnCli
|
||||||
switch (fragment.classType) {
|
switch (fragment.classType) {
|
||||||
case Task.TYPE_HABIT: {
|
case Task.TYPE_HABIT: {
|
||||||
fragment.tutorialStepIdentifier = "habits";
|
fragment.tutorialStepIdentifier = "habits";
|
||||||
fragment.tutorialText = context.getString(R.string.tutorial_habits);
|
fragment.tutorialTexts = Arrays.asList(context.getString(R.string.tutorial_overview),
|
||||||
|
context.getString(R.string.tutorial_habits_1),
|
||||||
|
context.getString(R.string.tutorial_habits_2),
|
||||||
|
context.getString(R.string.tutorial_habits_3),
|
||||||
|
context.getString(R.string.tutorial_habits_4));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Task.FREQUENCY_DAILY: {
|
case Task.FREQUENCY_DAILY: {
|
||||||
fragment.tutorialStepIdentifier = "dailies";
|
fragment.tutorialStepIdentifier = "dailies";
|
||||||
fragment.tutorialText = context.getString(R.string.tutorial_dailies);
|
fragment.tutorialTexts = Arrays.asList(context.getString(R.string.tutorial_dailies_1),
|
||||||
|
context.getString(R.string.tutorial_dailies_2));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Task.TYPE_TODO: {
|
case Task.TYPE_TODO: {
|
||||||
fragment.tutorialStepIdentifier = "todos";
|
fragment.tutorialStepIdentifier = "todos";
|
||||||
fragment.tutorialText = context.getString(R.string.tutorial_todos);
|
fragment.tutorialTexts = Arrays.asList(context.getString(R.string.tutorial_todos_1),
|
||||||
|
context.getString(R.string.tutorial_todos_2));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Task.TYPE_REWARD: {
|
case Task.TYPE_REWARD: {
|
||||||
fragment.tutorialStepIdentifier = "rewards";
|
fragment.tutorialStepIdentifier = "rewards";
|
||||||
fragment.tutorialText = context.getString(R.string.tutorial_rewards);
|
fragment.tutorialTexts = Arrays.asList(context.getString(R.string.tutorial_rewards_1),
|
||||||
|
context.getString(R.string.tutorial_rewards_2));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
package com.habitrpg.android.habitica.ui.views;
|
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableStringBuilder;
|
||||||
|
import android.text.style.ForegroundColorSpan;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import com.habitrpg.android.habitica.R;
|
||||||
|
|
||||||
|
// http://stackoverflow.com/a/6700718/1315039
|
||||||
|
public class Typewriter extends android.support.v7.widget.AppCompatTextView {
|
||||||
|
|
||||||
|
private SpannableStringBuilder stringBuilder;
|
||||||
|
private Object visibleSpan;
|
||||||
|
private Object hiddenSpan;
|
||||||
|
private int index;
|
||||||
|
private long delay = 30;
|
||||||
|
|
||||||
|
|
||||||
|
public Typewriter(Context context) {
|
||||||
|
super(context);
|
||||||
|
setupTextColors(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Typewriter(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
setupTextColors(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupTextColors(Context context) {
|
||||||
|
visibleSpan = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.textColorLight));
|
||||||
|
hiddenSpan = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.transparent));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Handler handler = new Handler();
|
||||||
|
private Runnable characterAdder = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
stringBuilder.setSpan(visibleSpan, 0, index++, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
||||||
|
setText(stringBuilder);
|
||||||
|
if(index <= stringBuilder.length()) {
|
||||||
|
handler.postDelayed(characterAdder, delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public void animateText(CharSequence text) {
|
||||||
|
stringBuilder = new SpannableStringBuilder(text);
|
||||||
|
stringBuilder.setSpan(hiddenSpan, 0, stringBuilder.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
setText(stringBuilder);
|
||||||
|
handler.removeCallbacks(characterAdder);
|
||||||
|
handler.postDelayed(characterAdder, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCharacterDelay(long millis) {
|
||||||
|
delay = millis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAnimating() {
|
||||||
|
return index < stringBuilder.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopTextAnimation() {
|
||||||
|
index = stringBuilder.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue